1. 程式人生 > >day 30 1.作業系統原理 2. Process 模組學習

day 30 1.作業系統原理 2. Process 模組學習

程序:

起源:程序的概念起源於作業系統,是作業系統最核心的概念,也是作業系統提供的最古老也是最重要的抽象概念之一。作業系統的其他所有內容都是圍繞程序的概念展開的。所以想要真正瞭解程序,必須事先了解作業系統.

  什麼是作業系統?

  #一 作業系統的作用:
      1:隱藏醜陋複雜的硬體介面,提供良好的抽象介面
      2:管理、排程程序,並且將多個程序對硬體的競爭變得有序

  #二 多道技術: ※※※
      1.產生背景:針對單核,實現併發
      ps:
      現在的主機一般是多核,那麼每個核都會利用多道技術
      有4個cpu,運行於cpu1的某個程式遇到io阻塞,會等到io結束再重新排程,會被排程到4個
      cpu中的任意一個,具體由作業系統排程演算法決定。
      
      2.空間上的複用:如記憶體中同時有多道程式
      3.時間上的複用:複用一個cpu的時間片
         強調:遇到io切,佔用cpu時間過長也切,核心在於切之前將程序的狀態儲存下來,這樣
              才能保證下次切換回來時,能基於上次切走的位置繼續執行

 

 


什麼是程序?
  程序(Process)是計算機中的程式關於某資料集合上的一次執行活動,是系統進行資源分配和排程的基本單位,
  是作業系統結構的基礎。在早期面向程序設計的計算機結構中,程序是程式的基本執行實體;
  在當代面向執行緒設計的計算機結構中,程序是執行緒的容器。程式是指令、資料及其組織形式的描述,程序是程式的實體。
  我們自己在python檔案中寫了一些程式碼,這叫做程式,執行這個python檔案的時候,這叫做程序。
        
  程序的特徵:
  
  動態性:程序的實質是程式在多道程式系統中的一次執行過程,程序是動態產生,動態消亡的。
  併發性:任何程序都可以同其他程序一起併發執行
  獨立性:程序是一個能獨立執行的基本單位,同時也是系統分配資源和排程的獨立單位;
  非同步性:由於程序間的相互制約,使程序具有執行的間斷性,即程序按各自獨立的、不可預知的速度向前推進
  結構特徵:程序由程式、資料和程序控制塊三部分組成。   多個不同的程序可以包含相同的程式:一個程式在不同的資料集裡就構成不同的程序,能得到不同的結果;但是執行過程中,程式不能發生改變。


程序的三種狀態: 就緒<-->執行-->阻塞-->就緒

 

 

同步\非同步\阻塞\非阻塞(重點)

 

 

multiprocess模組

1.process模組介紹

   process模組是一個建立程序的模組,藉助這個模組,就可以完成程序的建立

Process([group [, target [, name [, args [, kwargs]]]]]),由該類例項化得到的物件,表示一個子程序中的任務(尚未啟動)

強調:
1. 需要使用關鍵字的方式來指定引數
2. args指定的為傳給target函式的位置引數,是一個元組形式,必須有逗號

-------------------------------------------------------------------------------

程式碼示範:

 

#當前檔名稱為test.py
# from multiprocessing import Process # # def func(): # print(12345) # # if __name__ == '__main__': #windows 下才需要寫這個,這和系統建立程序的機制有關係,不用深究,記著windows下要寫就好啦 # #首先我運行當前這個test.py檔案,執行這個檔案的程式,那麼就產生了程序,這個程序我們稱為主程序 # # p = Process(target=func,) #將函式註冊到一個程序中,p是一個程序物件,此時還沒有啟動程序,只是建立了一個程序物件。並且func是不加括號的,因為加上括號這個函式就直接運行了對吧。 # p.start() #告訴作業系統,給我開啟一個程序,func這個函式就被我們新開的這個程序執行了,而這個程序是我主程序執行過程中創建出來的,所以稱這個新建立的程序為主程序的子程序,而主程序又可以稱為這個新程序的父程序。
          #而這個子程序中執行的程式,相當於將現在這個test.py檔案中的程式copy到一個你看不到的python檔案中去執行了,就相當於當前這個檔案,被另外一個py檔案import過去並執行了。
          #start並不是直接就去執行了,我們知道程序有三個狀態,程序會進入程序的三個狀態,就緒,(被排程,也就是時間片切換到它的時候)執行,阻塞,並且在這個三個狀態之間不斷的轉換,等待cpu執行時間片到了。 # print('*' * 10) #這是主程序的程式,上面開啟的子程序的程式是和主程序的程式同時執行的,我們稱為非同步
-------------------------------------------------------------

----------------------------------------------------------------
上面說了,我們通過主程序建立的子程序是非同步執行的,那麼我們就驗證一下,並且看一下子程序和主程序(也就是父程序)的ID號(講一下pid和ppid,使用pycharm舉例),來看看是否是父子關係。

import time
import os

#os.getpid()  獲取自己程序的ID號
#os.getppid() 獲取自己程序的父程序的ID號

from multiprocessing import Process

def func():
    print('aaaa')
    time.sleep(1)
    print('子程序>>',os.getpid())
    print('該子程序的父程序>>',os.getppid())
    print(12345)

if __name__ == '__main__': 
    #首先我運行當前這個檔案,執行的這個檔案的程式,那麼就產生了主程序

    p = Process(target=func,) 
    p.start() 
    print('*' * 10) 
    print('父程序>>',os.getpid())
    print('父程序的父程序>>',os.getppid())

#加上time和程序號給大家看一看結果:
#********** 首先打印出來了出程序的程式,然後列印的是子程序的,也就是子程序是非同步執行的,相當於主程序和子程序同時執行著,如果是同步的話,我們先執行的是func(),然後再列印主程序最後的10個*號。
#父程序>> 3308
#父程序的父程序>> 5916 #我執行的test.py檔案的父程序號,它是pycharm的程序號,看下面的截圖

#aaaa
#子程序>> 4536
#該子程序的父程序>> 3308 #是我主程序的ID號,說明主程序為它的父程序

#12345

---------------------------------------------------------------------
開啟windows下的工作管理員,看pycharm的pid程序號,是我們上面執行的test.py這個檔案主程序的父程序號:

 

----------------------------------------------------------------------------------------------------------

給要執行的函式傳引數:

def func(x,y):
    print(x)
    time.sleep(1)
    print(y)

if __name__ == '__main__':

    p = Process(target=func,args=('姑娘','來玩啊!'))#這是func需要接收的引數的傳送方式。
    p.start()
    print('父程序執行結束!')

#執行結果:
父程序執行結束!
姑娘
來玩啊!

--------------------------------------------------------------------------------------------------------------

Process類中各方法的介紹:

1 p.start():啟動程序,並呼叫該子程序中的p.run() 
2 p.run():程序啟動時執行的方法,正是它去呼叫target指定的函式,我們自定義類的類中一定要實現該方法  
3 p.terminate():強制終止程序p,不會進行任何清理操作,如果p建立了子程序,該子程序就成了殭屍程序,使用該方法需要特別小心這種情況。如果p還儲存了一個鎖那麼也將不會被釋放,進而導致死鎖
4 p.is_alive():如果p仍然執行,返回True
5 p.join([timeout]):主執行緒等待p終止(強調:是主執行緒處於等的狀態,而p是處於執行的狀態)。timeout是可選的超時時間,需要強調的是,p.join只能join住start開啟的程序,而不能join住run開啟的程序  
-------------------------------------------
join方法的例子:
def func(x,y):
    print(x)
    time.sleep(1)
    print(y)

if __name__ == '__main__':

    p = Process(target=func,args=('姑娘','來玩啊!'))
    p.start()
    print('我這裡是非同步的啊!')  #這裡相對於子程序還是非同步的
    p.join()  #只有在join的地方才會阻塞住,將子程序和主程序之間的非同步改為同步
    print('父程序執行結束!')

#列印結果:
我這裡是非同步的啊!
姑娘
來玩啊!
父程序執行結束!
-----------------------------------------------



----------------------------------

怎麼樣開啟多個程序呢?for迴圈。並且我有個需求就是說,所有的子程序非同步執行,然後所有的子程序全部執行完之後,我再執行主程序,怎麼搞?
#下面的註釋按照編號去看,別忘啦!
import time
import os
from multiprocessing import Process

def func(x,y):
    print(x)
    # time.sleep(1) #程序切換:如果沒有這個時間間隔,那麼你會發現func執行結果是列印一個x然後一個y,再列印一個x一個y,不會出現列印多個x然後列印y的情況,因為兩個列印距離太近了而且執行的也非常快,但是如果你這段程式執行慢的話,你就會發現程序之間的切換了。
    print(y)

if __name__ == '__main__':

    p_list= []
    for i in range(10):
        p = Process(target=func,args=('姑娘%s'%i,'來玩啊!'))
        p_list.append(p)
        p.start()

    [ap.join() for ap in p_list] #4、這是解決辦法,前提是我們的子程序全部都已經去執行了,那麼我在一次給所有正在執行的子程序加上join,那麼主程序就需要等著所有子程序執行結束才會繼續執行自己的程式了,並且保障了所有子程序是非同步執行的。

        # p.join() #1、如果加到for迴圈裡面,那麼所有子程序包括父程序就全部變為同步了,因為for迴圈也是主程序的,迴圈第一次的時候,一個程序去執行了,然後這個程序就join住了,那麼for迴圈就不會繼續執行了,等著第一個子程序執行結束才會繼續執行for迴圈去建立第二個子程序。
        #2、如果我不想這樣的,也就是我想所有的子程序是非同步的,然後所有的子程序執行完了再執行主程序
    #p.join() #3、如果這樣寫的話,多次執行之後,你會發現會出現主程序的程式比一些子程序先執行完,因為我們p.join()是對最後一個子程序進行了join,也就是說如果這最後一個子程序先於其他子程序執行完,那麼主程序就會去執行,而此時如果還有一些子程序沒有執行完,而主程序執行
         #完了,那麼就會先列印主程序的內容了,這個cpu排程程序的機制有關係,因為我們的電腦可能只有4個cpu,我的子程序加上住程序有11個,雖然我for迴圈是按順序起程序的,但是作業系統一定會按照順序給你執行你的程序嗎,答案是不會的,作業系統會按照自己的演算法來分配進
              #程給cpu去執行,這裡也解釋了我們打印出來的子程序中的內容也是沒有固定順序的原因,因為列印結果也需要呼叫cpu,可以理解成程序在爭搶cpu,如果同學你想問這是什麼演算法,這就要去研究作業系統啦。那我們的想所有子程序非同步執行,然後再執行主程序的這個需求怎麼解決啊
    print('不要錢~~~~~~~~~~~~~~~~!')

-------------------------------------



-------------------------------------
程序的建立第二種方法(繼承)

class MyProcess(Process): #自己寫一個類,繼承Process類
    #我們通過init方法可以傳引數,如果只寫一個run方法,那麼沒法傳引數,因為建立物件的是傳參就是在init方法裡面,面向物件的時候,我們是不是學過
    def __init__(self,person):
        super().__init__()
        self.person=person
    def run(self):
        print(os.getpid())
        print(self.pid)
        print(self.pid)
        print('%s 正在和女主播聊天' %self.person)
    # def start(self):
    #     #如果你非要寫一個start方法,可以這樣寫,並且在run方法前後,可以寫一些其他的邏輯
    #     self.run()
if __name__ == '__main__':
    p1=MyProcess('Jedan')
    p2=MyProcess('太白')
    p3=MyProcess('alexDSB')

    p1.start() #start內部會自動呼叫run方法
    p2.start()
    # p2.run()
    p3.start()


    p1.join()
    p2.join()
    p3.join()
------------------------------------------

程序之間的資料是隔離的!!!!!!!!!!!!!!!!!!!!!!!