python 之進程篇

多線程給咱們的感受python

  1.由於GIL的存在,一個進程的多線程同一時刻只能進去一個,感受是假的併發數據庫

  2.只適合I/O密集型的任務多線程

  3.針對計算密集型,就掛了(變成串行了)併發

在python中想要充分利用多核cpu的優點,就可用多進程這個技術---multiprocessingapp

        multiprocessing是多進程的一個管理包。包含 Process、Queue、Pipe、Lock等組件。與thread相似異步

  該Process對象與Thread對象的用法相同,也有start(), run(), join()的方法。此外multiprocessing包中也有Lock/Event/Semaphore/Condition類 (這些對象能夠像多線程那樣,經過參數傳遞給各個進程),用以同步進程,其用法與threading包中的同名類一致。因此,multiprocessing的很大一部份與threading使用同一套API,只不過換到了多進程的情境。async

但在使用這些共享API的時候,咱們要注意如下幾點:ide

  • 在UNIX平臺上,當某個進程終結以後,該進程須要被其父進程調用wait,不然進程成爲殭屍進程(Zombie)。因此,有必要對每一個Process對象調用join()方法 (實際上等同於wait)。對於多線程來講,因爲只有一個進程,因此不存在此必要性。
  • multiprocessing提供了threading包中沒有的IPC(好比Pipe和Queue),效率上更高。應優先考慮Pipe和Queue,避免使用Lock/Event/Semaphore/Condition等同步方式 (由於它們佔據的不是用戶進程的資源)。
  • 多進程應該避免共享資源。在多線程中,咱們能夠比較容易地共享資源,好比使用全局變量或者傳遞參數。在多進程狀況下,因爲每一個進程有本身獨立的內存空間,以上方法並不合適。此時咱們能夠經過共享內存和Manager的方法來共享資源。但這樣作提升了程序的複雜度,並由於同步的須要而下降了程序的效率。

簡單的例子:函數

from multiprocessing import Process
import os
def info(name):
    print(name)
    print(os.getppid())#在主進程運行的是的是這個是pychar的pid
    print(os.getpid())

if __name__ == "__main__":
    info("main")
    p=Process(target=info,args=("bob",))
    p.start()
    p.join()
View Code

進程之間通信

1. Queue()  注意這個不一樣於進程queue。  每一個進程之間使用pickle序列化實現

2. Pipe()

queue代碼:注意q要當參數 傳遞給函數,否則沒法使用。由於進程之間數據默認不共享的。ui

from multiprocessing import Process, Queue

def f(q,n):
    q.put([42, n, 'hello'])

if __name__ == '__main__':
    q = Queue()
    p_list=[]
    for i in range(3):
        p = Process(target=f, args=(q,i))
        p_list.append(p)
        p.start()
    print(q.get())
    print(q.get())
    print(q.get())
    for i in p_list:
            i.join()
View Code

Pipe代碼

from multiprocessing import Process, Pipe
 
def f(conn):
    conn.send([42, None, 'hello'])
    conn.close()
 
if __name__ == '__main__':
    parent_conn, child_conn = Pipe()
    p = Process(target=f, args=(child_conn,))
    p.start()
    print(parent_conn.recv())   # prints "[42, None, 'hello']"
    p.join()
View Code

進程之間數據共享:Manager組件

from multiprocessing import Process, Manager

def f(d, l,n):
    d[n] = '1'
    d['2'] = 2
    d[0.25] = None
    l.append(n)
    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,i))
            p.start()
            p_list.append(p)
        for res in p_list:
            res.join()

        print(d)
        print(l)
View Code

    這裏存在一個問題:數據共享 是否是要加鎖

進程之間的數據同步LOCK:

用法與線程的同樣:主要是爲了防止進程搶佔屏幕輸出,避免輸出錯亂

from multiprocessing import Process, Lock

def f(l, i):
    l.acquire()
    try:
        print('hello world', i)
    finally:
        l.release()

if __name__ == '__main__':
    lock = Lock()

    for num in range(10):
        Process(target=f, args=(lock, num)).start()
View Code

 

 進程池:                                                                                                                                                     

兩種方法:
  • pool.apply
  • pool.apply_async
from multiprocessing import Pool
import os,time
def Foo(i):
    time.sleep(2)
    print("子進程",i,os.getpid())
def Bar(arg):
    print("Exec done",arg,os.getpid())
if __name__=="__main__":
    pool = Pool(3) #已經啓動了10個進程,可是同一時刻只能有3個進程執行
    for i in range(10):
        #pool.apply(func=Foo,args=(i,)) #串行效果
        #pool.apply_async(func=Foo,args=(i,))#異步方法,爲了顯示效果,必須加上,join。
        pool.apply_async(func=Foo, args=(i,),callback=Bar) #異步使用回調函數,可是這個回調是在主進程中執行的,列如:在數據庫鏈接的時候,若是在子進程鏈接,每一個都要打開新的,很差
    pool.close()
    pool.join()#join以前,必須加上close,注意:close在前。
View Code
相關文章
相關標籤/搜索