理解python的多進程編程

來源:互聯網
上載者:User
下面小編就為大家帶來一篇深入理解python多進程編程。小編覺得挺不錯的,現在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

1、python多進程編程背景

python中的多進程最大的好處就是充分利用多核cpu的資源,不像python中的多線程,受制於GIL的限制,從而只能進行cpu分配,在python的多進程中,適合於所有的場合,基本上能用多線程的,那麼基本上就能用多進程。

在進行多進程編程的時候,其實和多線程差不多,在多線程的包threading中,存在一個線程類Thread,在其中有三種方法來建立一個線程,啟動線程,其實在多進程編程中,存在一個進程類Process,也可以使用那集中方法來使用;在多線程中,記憶體中的資料是可以直接共用的,例如list等,但是在多進程中,記憶體資料是不能共用的,從而需要用單獨的資料結構來處理共用的資料;在多線程中,資料共用,要保證資料的正確性,從而必須要有所,但是在多進程中,鎖的考慮應該很少,因為進程是不共用記憶體資訊的,進程之間的互動資料必須要通過特殊的資料結構,在多進程中,主要的內容如:

2、多進程的類Process

多進程的類Process和多線程的類Thread差不多的方法,兩者的介面基本相同,具體看以下的代碼:

#!/usr/bin/env pythonfrom multiprocessing import Processimport osimport timedef func(name):  print 'start a process'  time.sleep(3)  print 'the process parent id :',os.getppid()  print 'the process id is :',os.getpid()if __name__ =='__main__':  processes = []  for i in range(2):    p = Process(target=func,args=(i,))    processes.append(p)  for i in processes:    i.start()  print 'start all process'  for i in processes:    i.join()    #pass  print 'all sub process is done!'

在上面例子中可以看到,多進程和多線程的API介面是一樣一樣的,顯示建立進程,然後進行start開始運行,然後join等待進程結束。

在需要執行的函數中,列印出了進程的id和pid,從而可以看到父進程和子進程的id號,在linu中,進程主要是使用fork出來的,在建立進程的時候可以查詢到父進程和子進程的id號,而在多線程中是無法找到線程的id,執行效果如下:

start all processstart a processstart a processthe process parent id : 8036the process parent id : 8036the process id is : 8037the process id is : 8038all sub process is done!

在作業系統中查詢的id的時候,最好用pstree,清晰:

├─sshd(1508)─┬─sshd(2259)───bash(2261)───python(7520)─┬─python(7521)    │      │                    ├─python(7522)    │      │                    ├─python(7523)    │      │                    ├─python(7524)    │      │                    ├─python(7525)    │      │                    ├─python(7526)    │      │                    ├─python(7527)    │      │                    ├─python(7528)    │      │                    ├─python(7529)    │      │                    ├─python(7530)    │      │                    ├─python(7531)    │      │                    └─python(7532)

在進行啟動並執行時候,可以看到,如果沒有join語句,那麼主進程是不會等待子進程結束的,是一直會執行下去,然後再等待子進程的執行。

在多進程的時候,說,我怎麼得到多進程的傳回值呢?然後寫了下面的代碼:

#!/usr/bin/env pythonimport multiprocessingclass MyProcess(multiprocessing.Process):  def __init__(self,name,func,args):    super(MyProcess,self).__init__()    self.name = name    self.func = func    self.args = args    self.res = ''  def run(self):    self.res = self.func(*self.args)    print self.name    print self.res    return (self.res,'kel')def func(name):  print 'start process...'  return name.upper()if __name__ == '__main__':  processes = []  result = []  for i in range(3):    p = MyProcess('process',func,('kel',))    processes.append(p)  for i in processes:    i.start()  for i in processes:    i.join()  for i in processes:    result.append(i.res)  for i in result:    print i

嘗試從結果中傳回值,從而在主進程中得到子進程的傳回值,然而,,,並沒有結果,後來一想,在進程中,進程之間是不共用記憶體的 ,那麼使用list來存放資料顯然是不可行的,進程之間的互動必須依賴於特殊的資料結構,從而以上的代碼僅僅是執行進程,不能得到進程的傳回值,但是以上代碼修改為線程,那麼是可以得到傳回值的。

3、進程間的互動Queue

進程間互動的時候,首先就可以使用在多線程裡面一樣的Queue結構,但是在多進程中,必須使用multiprocessing裡的Queue,代碼如下:

#!/usr/bin/env pythonimport multiprocessingclass MyProcess(multiprocessing.Process):  def __init__(self,name,func,args):    super(MyProcess,self).__init__()    self.name = name    self.func = func    self.args = args    self.res = ''  def run(self):    self.res = self.func(*self.args)def func(name,q):  print 'start process...'  q.put(name.upper())if __name__ == '__main__':  processes = []  q = multiprocessing.Queue()  for i in range(3):    p = MyProcess('process',func,('kel',q))    processes.append(p)  for i in processes:    i.start()  for i in processes:    i.join()  while q.qsize() > 0:    print q.get()

其實這個是上面例子的改進,在其中,並沒有使用什麼其他的代碼,主要就是使用Queue來儲存資料,從而可以達到進程間交換資料的目的。

在進行使用Queue的時候,其實用的是socket,感覺,因為在其中使用的還是發送send,然後是接收recv。

在進行資料互動的時候,其實是父進程和所有的子進程進行資料互動,所有的子進程之間基本是沒有互動的,除非,但是,也是可以的,例如,每個進程去Queue中取資料,但是這個時候應該是要考慮鎖,不然可能會造成資料混亂。

4、 進程之間互動Pipe

在進程之間互動資料的時候還可以使用Pipe,代碼如下:

#!/usr/bin/env pythonimport multiprocessingclass MyProcess(multiprocessing.Process):  def __init__(self,name,func,args):    super(MyProcess,self).__init__()    self.name = name    self.func = func    self.args = args    self.res = ''  def run(self):    self.res = self.func(*self.args)def func(name,q):  print 'start process...'  child_conn.send(name.upper())if __name__ == '__main__':  processes = []  parent_conn,child_conn = multiprocessing.Pipe()  for i in range(3):    p = MyProcess('process',func,('kel',child_conn))    processes.append(p)  for i in processes:    i.start()  for i in processes:    i.join()  for i in processes:    print parent_conn.recv()

在以上代碼中,主要是使用Pipe中返回的兩個socket來進行傳輸和接收資料,在父進程中,使用的是parent_conn,在子進程中使用的是child_conn,從而子進程發送資料的方法send,而在父進程中進行接收方法recv

最好的地方在於,明確的知道收發的次數,但是如果某個出現異常,那麼估計pipe不能使用了。

5、進程池pool

其實在使用多進程的時候,感覺使用pool是最方便的,在多線程中是不存在pool的。

在使用pool的時候,可以限制每次的進程數,也就是剩餘的進程是在排隊,而只有在設定的數量的進程在運行,在預設的情況下,進程是cpu的個數,也就是根據multiprocessing.cpu_count()得出的結果。

在poo中,有兩個方法,一個是map一個是imap,其實這兩方法超級方便,在執行結束之後,可以得到每個進程的返回結果,但是缺點就是每次的時候,只能有一個參數,也就是在執行的函數中,最多是只有一個參數的,否則,需要使用組合參數的方法,代碼如下所示:

#!/usr/bin/env pythonimport multiprocessingdef func(name):  print 'start process'  return name.upper()if __name__ == '__main__':  p = multiprocessing.Pool(5)  print p.map(func,['kel','smile'])  for i in p.imap(func,['kel','smile']):    print i

在使用map的時候,直接返回的一個是一個list,從而這個list也就是函數執行的結果,而在imap中,返回的是一個由結果組成的迭代器,如果需要使用多個參數的話,那麼估計需要*args,從而使用參數args。

在使用apply.async的時候,可以直接使用多個參數,如下所示:

#!/usr/bin/env pythonimport multiprocessingimport timedef func(name):  print 'start process'  time.sleep(2)  return name.upper()if __name__ == '__main__':  results = []  p = multiprocessing.Pool(5)  for i in range(7):    res = p.apply_async(func,args=('kel',))    results.append(res)  for i in results:    print i.get(2.1)

在進行得到各個結果的時候,注意使用了一個list來進行append,要不然在得到結果get的時候會阻塞進程,從而將多進程編程了單進程,從而使用了一個list來存放相關的結果,在進行得到get資料的時候,可以設定逾時時間,也就是get(timeout=5),這種設定。

總結:

在進行多進程編程的時候,注意進程之間的互動,在執行函數之後,如何得到執行函數的結果,可以使用特殊的資料結構,例如Queue或者Pipe或者其他,在使用pool的時候,可以直接得到結果,map和imap都是直接得到一個list和可迭代對象,而apply_async得到的結果需要用一個list裝起來,然後得到每個結果。

以上這篇深入理解python多進程編程就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支援topic.alibabacloud.com。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.