Python進程

Python在2.6引入了多進程的機制,並提供了豐富的組件及api以方便編寫併發應用。multiprocessing包的組件Process, Queue, Pipe, Lock等組件提供了與多線程類似的功能。使用這些組件,可以方便地編寫多進程併發程序。

多進程實例:

import os
from multiprocessing import Process

def info(title):
   print(title)
   print('module name:', __name__)
   print('parent process:', os.getppid())
   print('process id:', os.getpid())
   print("\n\n")

def f(name):
   info('\033[31;1mfunction f\033[0m')
   print('hello', name)

if __name__ == '__main__':
   info('\033[32;1mmain process line\033[0m')
   p = Process(target=info, args=('bob',))
   p.start()
   p.join()

實例化一個Process必須要指定target和args。target是新的進程的入口方法,可以認爲是main方法。args是該方法的參數列表。啓動進程類似於啓動Thread,必須要調用start方法。也可以繼承Process,覆蓋run方法,在run方法中實現該進程的邏輯。調用join方法會阻塞當前調用進程,直到被調用進程運行結束。

手工終止一個進程可以調用terminate方法,在UNIX系統中,該方法會發送SIGTERM信號量,而在windows系統中,會藉助TerminateProcess方法。需要注意的是,exit處理邏輯並不會被執行,該進程的子進程不會被終止,他們只會變成孤兒進程。

進程間通訊

Queue

Queue是多進程安全的隊列,可以使用Queue實現多進程之間的數據傳遞。put方法用以插入數據到隊列中,put方法還有兩個可選參數:blocked和timeout。如果blocked爲True(默認值),並且timeout爲正值,該方法會阻塞timeout指定的時間,直到該隊列有剩餘的空間。如果超時,會拋出Queue.Full異常。如果blocked爲False,但該Queue已滿,會立即拋出Queue.Full異常。

get方法可以從隊列讀取並且刪除一個元素。同樣,get方法有兩個可選參數:blocked和timeout。如果blocked爲True(默認值),並且timeout爲正值,那麼在等待時間內沒有取到任何元素,會拋出Queue.Empty異常。如果blocked爲False,有兩種情況存在,如果Queue有一個值可用,則立即返回該值,否則,如果隊列爲空,則立即拋出Queue.Empty異常。Queue的一段示例代碼:

from multiprocessing import Process, Queue

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

if __name__ == '__main__':
   q = Queue()
   p = Process(target=f, args=(q,))
   p2 = Process(target=f, args=(q,))
   p.start()
   p2.start()
   print('data1:',q.get())    # prints "[42, None, 'hello']"
   
print('data2:',q.get())
   p.join()

Pipes

Pipe方法返回(conn1, conn2)代表一個管道的兩個端。Pipe方法有duplex參數,如果duplex參數爲True(默認值),那麼這個管道是全雙工模式,也就是說conn1和conn2均可收發。duplex爲False,conn1只負責接受消息,conn2只負責發送消息。

send和recv方法分別是發送和接受消息的方法。例如,在全雙工模式下,可以調用conn1.send發送消息,conn1.recv接收消息。如果沒有消息可接收,recv方法會一直阻塞。如果管道已經被關閉,那麼recv方法會拋出EOFError。

from multiprocessing import Process, Pipe

def send(conn):
   conn.send("Hello World")
   conn.close()

if __name__ == '__main__':
   parent_conn, child_conn = Pipe()
   p = Process(target=send, args=(child_conn,))
   p.start()
   print(parent_conn.recv())

Managers

from multiprocessing import Process, Manager

def f(d, l):
   d[1] = '1'
   
d['2'] = 2
   
d[0.25] = None
   
l.append('a')
   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)

進程同步

multiprocessing包提供了Condition, Event, Lock, RLock, Semaphore等組件可用於同步。下面是使用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()

進程池  

進程池內部維護一個進程序列,當使用時,則去進程池中獲取一個進程,如果進程池序列中沒有可供使用的進進程,那麼程序就會等待,直到進程池中有可用進程爲止。

進程池中有兩個方法:

  • apply

  • apply_async

from  multiprocessing import Process,Pool,freeze_support
import time

def Foo(i):
   time.sleep(2)
   return i+100

def Bar(arg):
   print('-->exec done:',arg)


if __name__ == '__main__':
       freeze_support()
       pool = Pool(3)  
       for i in range(10):
           pool.apply_async(func=Foo, args=(i,),callback=Bar)  # 異步
           #pool.apply(func=Foo, args=(i,))    # 同步無回調機制

       
print('end')
       pool.close()
       pool.join()  #進程池中進程執行完畢後再關閉,如果註釋,那麼程序直接關閉。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章