python之進程

1,什麼是進程呢?python

進程(Process)是計算機中的關於某數據集合上的一次運算,是系統進行資源分配和調度的基本單位,是操做系統結構的基礎。進程是程序的實體。linux

動態性:進程的實質是程序在多道程序系統中的一次執行過程,進程是動態產生,動態消亡的。 併發性:任何進程均可以同其餘進程一塊兒併發執行 獨立性:進程是一個能獨立運行的基本單位,同時也是系統分配資源和調度的獨立單位; 異步性:因爲進程間的相互制約,使進程具備執行的間斷性,即進程按各自獨立的、不可預知的速度向前推動 結構特徵:進程由程序、數據和進程控制塊三部分組成。 多個不一樣的進程能夠包含相同的程序:一個程序在不一樣的數據集裏就構成不一樣的進程,能獲得不一樣的結果;可是執行過程當中,程序不能發生改變。
進程的特徵
程序是指令和數據的有序集合,其自己沒有任何運行的含義,是一個靜態的概念。 而進程是程序在處理機上的一次執行過程,它是一個動態的概念。 程序能夠做爲一種軟件資料長期存在,而進程是有必定生命期的。 程序是永久的,進程是暫時的。
程序與進程的區別

同一個程序執行兩次,就會在操做系統中出現兩個進程,能夠同時運行一個軟件,分別作不一樣的事情也不會混亂。算法

2,進程調度json

要想多個進程交替運行,操做系統必須對這些進程進行調度,須要進程調度算法。安全

(1)先來先服務調度算法服務器

(2)短做業優先調度算法網絡

(3)時間片輪轉發session

(4)多級反饋隊列:設置多個就緒隊列,爲各個隊列賦予不一樣優先級。優先級逐個下降,當一個程序在時間片仍未執行完,便加入到下一對列,直到執行完。每當有新進程進來,優先執行。併發

3,進程的並行與併發app

並行:並行是指二者同時執行,例:比賽,兩我的都在不停的往前跑(資源夠用。好比三個線程,四核的cpu)

併發:併發是指在資源有限的狀況下,二者交替輪流使用資源。(單核cpu)A走一段hou

,讓B走一段,B用完後在給A,交替使用。

區別:

並行:是從微觀上,就是在一個精確的時間片刻,有不一樣的程序在執行,要求必須有多個處理器。

併發:是從宏觀上,在一個時間段能夠看出同時執行的,好比一個服務器同時處理多個session

4,同步異步阻塞非阻塞

操做系統調度算法控制時,程序會進入幾個狀態:就緒,運行,阻塞。

(1)同步與異步

同步:完成一個任務須要依賴另外一個任務,只等別依賴的任務完成後,才能執行本身的。

異步:不須要等待依賴任務完後成,只需通知被依賴的任務執行。

(2)阻塞非阻塞

阻塞:程序中止不在執行

5,進程的建立與結束

multiprocess模塊

(1)

Process([group [, target [, name [, args [, kwargs]]]]]),由該類實例化獲得的對象,表示一個子進程中的任務(還沒有啓動) 強調: 1. 須要使用關鍵字的方式來指定參數 2. args指定的爲傳給target函數的位置參數,是一個元組形式,必須有逗號 參數介紹: 1 group參數未使用,值始終爲None 2 target表示調用對象,即子進程要執行的任務 3 args表示調用對象的位置參數元組,args=(1,2,'egon',) 4 kwargs表示調用對象的字典,kwargs={'name':'egon','age':18} 5 name爲子進程的名稱
View Code
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開啓的進程
方法
1 p.daemon:默認值爲False,若是設爲True,表明p爲後臺運行的守護進程,當p的父進程終止時,p也隨之終止,而且設定爲True後,p不能建立本身的新進程,必須在p.start()以前設置 2 p.name:進程的名稱 3 p.pid:進程的pid 4 p.exitcode:進程在運行時爲None、若是爲–N,表示被信號N結束(瞭解便可) 5 p.authkey:進程的身份驗證鍵,默認是由os.urandom()隨機生成的32字符的字符串。這個鍵的用途是爲涉及網絡鏈接的底層進程間通訊提供安全性,這類鏈接只有在具備相同的身份驗證鍵時才能成功(瞭解便可)
屬性
在Windows操做系統中因爲沒有fork(linux操做系統中建立進程的機制),在建立子進程的時候會自動 import 啓動它的這個文件,而在 import 的時候又執行了整個文件。所以若是將process()直接寫在文件中就會無限遞歸建立子進程報錯。因此必須把建立子進程的部分使用if __name__ ==‘__main__’ 判斷保護起來,import 的時候  ,就不會遞歸運行了。
注意事項
# from multiprocessing import Process # import os # def func(i): # print('%d:子進程%d乾的事,父進程:%d'%(i,os.getpid(),os.getppid())) # # if __name__=='__main__': # p_lst=[] # for i in range(10): # p=Process(target=func,args=(i,)) # p.start() # p_lst.append(p) # # p.join() #等子進程執行完,才執行下面的 # for p in p_lst:p.join() # print('---主進程---')

多進程同時運行,子進程的執行順序不是根據啓動順序決定的。

(2)經過繼承Process類開啓進程。

import os from multiprocessing import Process class MyProcess(Process): def __init__(self,name): super().__init__() self.name=name def run(self):                                 #必須有run方法
        print(os.getpid()) print('%s 正在和女主播聊天' %self.name) p1=MyProcess('wupeiqi') p2=MyProcess('yuanhao') p3=MyProcess('nezha') p1.start() #start會自動調用run
p2.start() # p2.run()
p3.start() p1.join() p2.join() p3.join() print('主線程')

注:進程之間的數據不是共享的(數據的隔離問題)

from multiprocessing import Process def work(): global n n=0 print('子進程內: ',n) if __name__ == '__main__': n = 100 p=Process(target=work) p.start() print('主進程內: ',n)

5,守護進程

子進程會隨主進程的結束而結束。

主進程建立守護進程

       其一:守護進程會在主進程代碼執行結束後終止

       其二:守護進程內沒法再開子進程,不然拋異常。

 

# start 開啓一個進程 # join 用join可讓主進程等待子進程結束

# 守護進程 # 守護進程會隨着主進程的代碼執行結束而結束 # 正常的子進程沒有執行完的時候主進程要一直等着
import time from multiprocessing import Process def func(): print('--'*10) time.sleep(15) print('--'*10) def cal_time(): while True: time.sleep(1) print('過去了1秒') if __name__ == '__main__': p = Process(target=cal_time) p.daemon = True     # 必定在開啓進程以前設置
 p.start() p2 = Process(target=func)  # 15s
 p2.start() for i in range(100):    # 10s
        time.sleep(0.1) print('*'*i) p2.join() # 守護進程的進程的做用:
    # 會隨着主進程的代碼執行結束而結束,不會等待其餘子進程 # 守護進程 要在start以前設置 # 守護進程中 不能再開啓子進程
View Code

6,鎖

  當多個進程使用同一份數據資源的時候,就會引起數據安全或順序混亂問題

from multiprocessing import Lock

import time import json import random from multiprocessing import Lock from multiprocessing import Process def search(i): with open('ticket') as f: print(i,json.load(f)['count']) def get(i): with open('ticket') as f : ticket_num=json.load(f)['count'] time.sleep(random.random()) if ticket_num>0: with open('ticket','w') as f: json.dump({'count':ticket_num-1},f) print('%s買到票了'%i) else: print('%s沒買到票'%i) def task(i,lock): search(i) lock.acquire() #鎖,鑰匙
 get(i) lock.release() #還鑰匙

if __name__=='__main__': lock=Lock() for i in range(20): p=Process(target=task,args=(i,lock)) p.start()
搶票的例子
#加鎖能夠保證多個進程修改同一塊數據時,同一時間只能有一個任務能夠進行修改,即串行的修改,沒錯,速度是慢了,但犧牲了速度卻保證了數據安全。
雖然能夠用文件共享數據實現進程間通訊,但問題是: 1.效率低(共享數據基於文件,而文件是硬盤上的數據) 2.須要本身加鎖處理 #所以咱們最好找尋一種解決方案可以兼顧:一、效率高(多個進程共享一塊內存的數據)二、幫咱們處理好鎖問題。這就是mutiprocessing模塊爲咱們提供的基於消息的IPC通訊機制:隊列和管道。
隊列和管道都是將數據存放於內存中 隊列又是基於(管道+鎖)實現的,可讓咱們從複雜的鎖問題中解脫出來, 咱們應該儘可能避免使用共享數據,儘量使用消息傳遞和隊列,避免處理複雜的同步和鎖問題,並且在進程數目增多時,每每能夠得到更好的可獲展性。

7,信號量(from multiprocessing import Semaphore)

信號量基於內部的計數器,能夠有多個鎖鑰匙。

import random import time from multiprocessing import Process from multiprocessing import Semaphore def sing(i,sem): sem.acquire() print('%s :進去 ktv '%i) time.sleep(random.randint(2,8)) print('%s : 離開 ktv'%i) sem.release() if __name__=='__main__': sem=Semaphore(5)          #鑰匙數,參數能夠設置
    for i in range(20): Process(target=sing,args=(i,sem)).start()
例子

8,事件(from multiprocessing import Event)

python線程的事件用於主線程控制其餘線程的執行,事件主要提供了三個方法 set、wait、clear。 事件處理的機制:全局定義了一個「Flag」,若是「Flag」值爲 False,那麼當程序執行 event.wait 方法時就會阻塞,若是「Flag」值爲True,那麼event.wait 方法時便再也不阻塞。 clear:將「Flag」設置爲False set:將「Flag」設置爲True
介紹
# import time # import random # from multiprocessing import Process # from multiprocessing import Event # # def traffic_light(e): # while True: # if e.is_set(): # e.is_set()是否阻塞 True就是綠燈 False就是紅燈 # time.sleep(3) # print('紅燈亮') # e.clear()  # else: # time.sleep(3) # print('綠燈亮') # e.set() # def car(i,e): # e.wait() # print('%s車經過'%i) # # if __name__=='__main__': # e=Event() # tra=Process(target=traffic_light,args=(e,)) # tra.start() # for i in range(100): # if i%6 == 0: # time.sleep(random.randint(1,3)) # car_pro=Process(target=car,args=(i,e)) # car_pro.start()
例子

9,隊列(from multiprocessing import Queue)

建立共享的進程隊列,Queue是多進程安全的隊列,可使用Queue實現多進程之間的數據傳遞。

Queue([maxsize]) 建立共享的進程隊列。maxsize是隊列中容許的最大項數。若是省略此參數,則無大小限制。底層隊列使用管道和鎖定實現。另外,還須要運行支持線程以便隊列中的數據傳輸到底層管道中。 Queue的實例q具備如下方法: q.get( [ block [ ,timeout ] ] ) 返回q中的一個項目。若是q爲空,此方法將阻塞,直到隊列中有項目可用爲止。block用於控制阻塞行爲,默認爲True. 若是設置爲False,將引起Queue.Empty異常(定義在Queue模塊中)。timeout是可選超時時間,用在阻塞模式中。若是在制定的時間間隔內沒有項目變爲可用,將引起Queue.Empty異常。 q.get_nowait( ) 同q.get(False)方法。 q.put(item [, block [,timeout ] ] ) 將item放入隊列。若是隊列已滿,此方法將阻塞至有空間可用爲止。block控制阻塞行爲,默認爲True。若是設置爲False,將引起Queue.Empty異常(定義在Queue庫模塊中)。timeout指定在阻塞模式中等待可用空間的時間長短。超時後將引起Queue.Full異常。 q.qsize() 返回隊列中目前項目的正確數量。此函數的結果並不可靠,由於在返回結果和在稍後程序中使用結果之間,隊列中可能添加或刪除了項目。在某些系統上,此方法可能引起NotImplementedError異常。 q.empty() 若是調用此方法時 q爲空,返回True。若是其餘進程或線程正在往隊列中添加項目,結果是不可靠的。也就是說,在返回和使用結果之間,隊列中可能已經加入新的項目。 q.full() 若是q已滿,返回爲True. 因爲線程的存在,結果也多是不可靠的(參考q.empty()方法)。
方法介紹
#1.進程之間通訊 可使用multiprocessing 的 Queue模塊 #2.隊列有兩種建立方式 第一種不傳參數 這個隊列就沒有長度限制 ;傳參數,建立一個有最大長度限制的隊列 #3.提供兩個重要方法;put get #4.qsize

from multiprocessing import Process from multiprocessing import Queue # def q_put(q): # q.put('hello') # # def q_get(q): # print(q.get()) # # if __name__ =='__main__': # q = Queue() # p = Process(target=q_put,args=(q,)) # p.start() # p1 = Process(target=q_get, args=(q,)) # p1.start()
View Code

生產者消費者模型

# 經過隊列實現了 主進程與子進程的通訊 子進程與子進程之間的通訊 # 生產者消費者模型

# 我要生產一個數據 而後 給一個函數 讓這個函數依賴這個數據進行運算 拿到結果 —— 同步過程

# 作包子 和 吃包子
import time def producer(q):  # 生產者
    for i in  range(100): q.put('包子%s'%i) def consumer(q): # 消費者
    for i in range(100): time.sleep(1) print(q.get()) if __name__ == '__main__': q = Queue(10)   # 托盤
    p = Process(target=producer,args=(q,)) p.start() c1 = Process(target=consumer, args=(q,)) c2 = Process(target=consumer, args=(q,)) c1.start() c2.start() # 首先 對於內存空間來講 每次只有不多的數據會在內存中 # 對於生產與消費之間的不平衡來講
    # 增長消費者或者增長生產者來調節效率
View Code
相關文章
相關標籤/搜索