import multiprocessing
import os, time
def info(title):
print(title)
# time.sleep(1)
print("Module name:", __name__)
print("Parent process id:", os.getppid()) #父進(jìn)程id
print("Current process id:", os.getpid()) #當(dāng)前進(jìn)程id
print("\n\n")
# if __name__ == "__main__": #啟動一個子進(jìn)程
# info("Main process")
# p = multiprocessing.Process(target=info, args=('Child process',))
# p.start()
if __name__ == "__main__": #啟動多個子進(jìn)程(查看結(jié)果)
info("Main process")
for i in range(10):
p = multiprocessing.Process(target=info, args=('Child process %s' %i,))
p.start()
注意:由于進(jìn)程之間的數(shù)據(jù)需要各自持有一份侍瑟,所以創(chuàng)建進(jìn)程需要的非常大的開銷尉咕。
進(jìn)程間通信
不同進(jìn)程之間內(nèi)存是不共享的,要想實(shí)現(xiàn)兩個進(jìn)程間的數(shù)據(jù)交換樱哼,有以下方法:
進(jìn)程隊列(Queue)
使用方法跟threading里的queue差不多(進(jìn)程Queue使用pickle數(shù)據(jù)傳遞)
import multiprocessing, time
def put_func(qq):
qq.put([12, None, "hello"])
# time.sleep(2)
# print("put:",qq.qsize())
def get_func(qq):
print(qq.get())
if __name__ == "__main__":
q = multiprocessing.Queue() #創(chuàng)建一個進(jìn)程Queue對象
puter = multiprocessing.Process(target=put_func,args=(q,)) #將Queue對象傳遞到新創(chuàng)建的子進(jìn)程中
puter.start()
geter = multiprocessing.Process(target=get_func, args=(q,))
geter.start()
Pipe
pipe()返回一對連接對象球恤,conn1, conn2代表了pipe的兩端辜昵。每個對象都有send()和recv()方法。
from multiprocessing import Pipe,Process
import time
# a_conn, b_conn = Pipe()
# a_conn.send(['a', 'f', 'e'])
# print(b_conn.recv())
def f(conn):
time.sleep(2)
conn.send(['a', 'b', 'c'])
def ff(conn):
print(conn.recv())
if __name__ == "__main__":
conn1, conn2 = Pipe()
p1 = Process(target=f, args=(conn2,))
p2 = Process(target=ff ,args=(conn1,))
# p1.daemon = True # 加上daemon屬性
# p2.daemon = True
p1.start()
p2.start()
Manager
Python實(shí)現(xiàn)多進(jìn)程間通信的方式有很多種咽斧,例如隊列堪置,管道等。但是這些方式只適用于多個進(jìn)程都是源于同一個父進(jìn)程的情況张惹。如果多個進(jìn)程不是源于同一個父進(jìn)程舀锨,只能用共享內(nèi)存,信號量等方式诵叁,但是這些方式對于復(fù)雜的數(shù)據(jù)結(jié)構(gòu)雁竞,例如Queue,dict,list等碑诉,使用起來比較麻煩彪腔,不夠靈活。
Manager是一種較為高級的多進(jìn)程通信方式进栽,它能支持Python支持的的任何數(shù)據(jù)結(jié)構(gòu)德挣。
它的原理是:先啟動一個ManagerServer進(jìn)程,這個進(jìn)程是阻塞的快毛,它監(jiān)聽一個socket格嗅,然后其他進(jìn)程(ManagerClient)通過socket來連接到ManagerServer,實(shí)現(xiàn)通信唠帝。
from multiprocessing import Process, Manager
import os
def f(d, l):
d[os.getpid()] = os.getpid()
d[1] = '1'
l.append(os.getpid())
print(l)
if __name__ == "__main__":
with Manager() as manager: #manager = multiprocessing.Manager()
d = manager.dict() ## 生成一個可在多個進(jìn)程間共享和傳遞的字典
l = manager.list(range(5)) ##生成一個可在多個進(jìn)程間共享和傳遞的列表
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)
進(jìn)程池
進(jìn)程池內(nèi)部維護(hù)一個進(jìn)程序列屯掖,當(dāng)使用時,則去進(jìn)程池中獲取一個進(jìn)程襟衰,如果進(jìn)程池序列中沒有可供使用的進(jìn)進(jìn)程贴铜,那么程序就會等待,直到進(jìn)程池中有可用進(jìn)程為止瀑晒。進(jìn)程池設(shè)置最好等于CPU核心數(shù)量
進(jìn)程池中有兩個方法:
? apply 串行
? apply_async
from multiprocessing import Process, Pool
import time, os
def Foo(i):
time.sleep(2)
return i+100
def Bar(arg):
print(os.getpid()) #使用的主進(jìn)程做的回調(diào)(os.getpid()值是一樣的)
print(arg)
if __name__ == '__main__':
pool = Pool(3) #進(jìn)程池同時可放3個進(jìn)程
for i in range(10):
# pool.apply(func=Foo, args=(i,))
pool.apply_async(func=Foo, args=(i,), callback=Bar) #callback回調(diào)绍坝,func執(zhí)行完畢后執(zhí)行回調(diào)函數(shù),注意:使用的主進(jìn)程做的回調(diào)
print('end')
pool.close() # 一定要先關(guān)閉進(jìn)程池再join
pool.join() #進(jìn)程池中的進(jìn)程執(zhí)行完畢后再關(guān)閉苔悦,如果注釋轩褐,程序就直接關(guān)閉了