初學Python——進程

什麼是進程?

  程序不能單獨執行,只有將程序裝載到內存中,系統爲它分配資源才能運行,而這種執行的過程就叫作進程。進程是操做系統調度的最小單位。app

  程序和進程的區別在於:程序是儲存在硬盤上指令的有序集合,是靜態的;進程是內存中程序的一次執行過程,屬於動態概念。async

線程和進程的區別:

進程是資源的集合,進程要在CPU執行,必需要建立線程,至少要有一個線程在運行。ide

  1.線程共享建立它的進程的地址空間。進程的內存空間是獨立的。函數

  2.線程能夠直接訪問其進程的數據段(不一樣線程共享同一個進程的數據),進程間不共享。ui

  3.線程能夠與其餘線程進行通訊,進程必須使用進程間通訊(中間代理)與同級進程進行通訊。spa

  4.新的線程很容易建立,新的進程須要父進克隆。操作系統

  5.線程能夠直接操做和控制同一進程內的其它線程,而進程只能操做子進程。線程

  6.對主線程的修改可能會影響到其它線程的行爲。對父進程的修改不會影響子進程(不刪除父進程的前提下)3d

 Python多進程的使用

Process 類用來描述一個進程對象。建立子進程的時候,只須要傳入一個執行函數和函數的參數便可完成 Process 示例的建立。代理

  star() 方法啓動進程。

  join() 方法實現進程間的同步,等待全部進程退出。

  close() 用來阻止多餘的進程涌入進程池 Pool 形成進程阻塞。

multiprocessing.Process(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)

  target 是函數名字,須要調用的函數

  args 函數須要的參數,以 元組 的形式傳入

 multiprocessing模塊的使用跟線程相似

import multiprocessing import threading import time def t_run(): print("線程號",threading.get_ident()) # 線程id


def run(name): time.sleep(1) print('hello', name) t = threading.Thread(target=t_run) t.start() if __name__ == '__main__': for i in range(10): p = multiprocessing.Process(target=run, args=(i,)) p.start()
multiprocessing

全部的進程都是由父進程啓動的,因此發現此程序的父進程ID正是PyCharm。

每一個進程都是相互獨立的,存在於不一樣的內存地址。

進程間通訊

  • 首先聲明一點,這裏所說的進程間通訊指的是父子進程之間的通訊機制。若是兩個進程間沒有關係,這裏的機制是沒法奏效的。
  • 通訊方式有:進程隊列Queue、管道通訊Pipe、共享數據Manger

1.進程隊列Queue

  進程隊列直接使用multiprocessing模塊的Queue類,不一樣於線程隊列的queue模塊。

import multiprocessing def f(q): q.put([42, None, 'hello']) q.put(30) if __name__ == '__main__': q = multiprocessing.Queue() p = multiprocessing.Process(target=f, args=(q,)) # 將隊列copy一份傳給子進程
 p.start() print(q.get())  # 在父進程中取出隊列中數據
    print(type(q.get())) p.join()
進程隊列

2.管道Pipe

  兩個進程在管道兩邊收發數據。

import multiprocessing '''Pipe管道實例,兩個進程在管道兩邊收發數據'''

def f(conn): conn.send([42, None, 'hello'])  # 發送數據
    print("child_conn接收:",conn.recv())   # 接收數據
 conn.close() def s(conn): conn.send("你好,紫禁城")  # 發送數據
    print("parent_conn接收:",conn.recv())   # 接收數據
 conn.close() if __name__ == '__main__': parent_conn, child_conn = multiprocessing.Pipe() # 管道實例,鏈接着兩個進程
    p = multiprocessing.Process(target=f, args=(child_conn,)) p2 = multiprocessing.Process(target=s,args=(parent_conn,)) p.start() p2.start() #print(parent_conn.recv()) # 父進程接收管道的數據
    #parent_conn.send("你好,紫禁城") # 父進程發送數據
 p.join() p2.join()
Pipe

3.進程間共享數據Manger

  使用Manger()能夠建立共享的數據,包括列表,字典,元組等多種類型。

from multiprocessing import Process, Manager def f(d, l): d[1] = '1' d['2'] = 2 d[0.25] = None l.append(1) print(l) if __name__ == '__main__': with Manager() as manager: d = manager.dict() l = manager.list(range(5)) p_list = [] for i in range(10): p = Process(target=f, args=(d, l)) p.start() p_list.append(p) for res in p_list: res.join() print(d) print(l)
Manger

Lock

  屏幕鎖,防止一個進程未打印完畢,另外一個進程插入

def f(l,i): l.acquire() print("hello",i) l.release() if __name__ == '__main__': l=Lock() for i in range(10): Process(target=f,args=(l,i)).start()
lock

進程池

在利用Python進行系統管理的時候,特別是同時操做多個文件目錄,或者遠程控制多臺主機,並行操做能夠節約大量的時間。當被操做對象數目不大時,能夠直接利用multiprocessing中的Process動態成生多個進程,10幾個還好,但若是是上百個,上千個目標,手動的去限制進程數量卻又太過繁瑣,這時候進程池Pool發揮做用的時候就到了。

Pool能夠提供指定數量的進程,供用戶調用,當有新的請求提交到pool中時,若是池尚未滿,那麼就會建立一個新的進程用來執行該請求;但若是池中的進程數已經達到規定最大值,那麼該請求就會等待,直到池中有進程結束,纔會建立新的進程來它。這裏有一個簡單的例子:

from multiprocessing import Process, Pool import time, os def Foo(i): time.sleep(5) print('in process[Foo]', os.getpid()) return i + 100
 
 
def Bar(arg):  # 父進程去執行,而不是子進程調用
    print('-->exec done:', arg) print('in process[Bar]', os.getpid()) if __name__ == '__main__': pool = Pool(5)  # 容許進程池裏同時放入5個進程 其餘多餘的進程處於掛起狀態
 
    for i in range(10): pool.apply_async(func=Foo, args=(i,), callback=Bar) # pool.apply(func=Foo, args=(i,)) 
 
    print('end:', os.getpid()) pool.close() # close() 必須在join()前被調用
    pool.join()   # 進程池中進程執行完畢後再關閉,若是註釋,那麼程序直接關閉。
進程池
  • pool.apply_async()用來向進程池提交目標請求。
  • pool.join()是用來等待進程池中的worker進程執行完畢,防止主進程在worker進程結束前結束。但pool.join()必須使用在pool.close()或者pool.terminate()以後。
  • close()terminate()的區別在於close()會等待池中的worker進程執行結束再關閉pool,而terminate()則是直接關閉。
  • result.successful()表示整個調用執行的狀態,若是還有worker沒有執行完,則會拋出AssertionError異常。    
  • 利用multiprocessing下的Pool能夠很方便的同時自動處理幾百或者上千個並行操做,腳本的複雜性也大大下降.
相關文章
相關標籤/搜索