這篇文章簡單介紹一下multiprocessing包中的進程池程管理工具Pool。如果你是第一次接觸python的多進程年碘,請先看一下我的前兩篇文章http://www.reibang.com/p/31bca20caec0和http://www.reibang.com/p/e7a5f3b2afcf傲诵。如果只想了解Pool栓拜,那就接著看吧。在上一篇文章中我們介紹了Process的主要應(yīng)用,使用Process可以建立一個進程盛险,如果建立多個進程可以使用多個Process建立不同的的進程對象揉忘,也可以使用for循環(huán)建立多個進程换淆,具體內(nèi)容請看我在簡書的上一篇文章。
我們引入進程池工具Pool,直接把進程扔到池里,根據(jù)池自身的特點對進程進行管理样勃,后面我會詳細(xì)介紹峭拘,這里只需要知道他是一個容器能夠夠使制定數(shù)量的進程在池中統(tǒng)一運行即可鸡挠,下面來看一段簡單的代碼:
# 多個進程同時運行沒有返回值
def f(name):
"""定義一個簡單的打印名字的函數(shù)"""
print('hello:', name)
if __name__ == '__main__':
name_list = ["小飛", "小倩", "是不是淘氣", "二妞"]
pool = Pool(processes=4) # 創(chuàng)建4個進程
for name in name_list:
pool.apply_async(f, (name,))
pool.close() # 關(guān)閉進程池姓惑,表示不能在往進程池中添加進程
pool.join() # 等待進程池中的所有進程執(zhí)行完畢唯沮,必須在close()之后調(diào)用
返回的結(jié)果為:
hello: 小飛
hello: 小倩
hello: 是不是淘氣
hello: 二妞
在上面的例子中我們使用Pool建立了一個可以存放四個進程的池于游,使用for循環(huán),將進程依次加入到進程池中担忧,對于每一個進程使用apply_async()方法建立進程芹缔。對于進程池Pool這個類,主要有兩種建立進程的方式一種是apply_async()瓶盛,另一種是map()最欠,這兩種類方法的解釋如下:
apply_async函數(shù)原型:
apply_async(func[, args=()[, kwds={}[, callback=None]]])
與apply用法一樣,但它是非阻塞且支持結(jié)果返回進行回調(diào)惩猫。
map 函數(shù)原型:
map(func, iterable[, chunksize=None])
Pool類中的map方法芝硬,與內(nèi)置的map函數(shù)用法行為基本一致,它會使進程阻塞直到返回結(jié)果轧房。
注意拌阴,雖然第二個參數(shù)是一個迭代器,但在實際使用中奶镶,必須在整個隊列都就緒后迟赃,程序才會運行子進程。
之前對close实辑、terminate捺氢、join方法已經(jīng)有了介紹,這里在介紹一次:
close()
關(guān)閉進程池(pool)剪撬,使其不在接受新的任務(wù)摄乒。
terminate()
結(jié)束工作進程,不在處理未處理的任務(wù)残黑。
join()
主進程阻塞等待子進程的退出馍佑,join方法必須在close或terminate之后使用。
上面的案例中梨水,每個進程都沒有返回值拭荤,下面介紹一個有返回值的,先看一下代碼疫诽,我再來解釋:
# 多個進程同時運行舅世,每個進程都有返回值
def add_part(part):
"""計算一個列表的開始到末尾的累加
:param part:長度為二的列表
:return: 返回累加的和
"""
result = 0
for value in range(part[0], part[1] + 1):
result += value
return result
if __name__ == '__main__':
# 第一種方式使用pool.apply_async(),使用pool.get()來獲取結(jié)果
startTime = datetime.datetime.now()
part_result = []
pool = Pool(processes=2)
for i in [[0, 500000000], [500000001, 1000000000]]:
part_result.append(pool.apply_async(add_part, (i,)))
pool.close()
pool.join()
add_result = 0
for index, value in enumerate(part_result, 0):
print("第%s個進程的結(jié)果為%s" % (index, value.get()))
add_result += value.get()
print("結(jié)果為", add_result)
print(datetime.datetime.now() - startTime)
這里我們繼續(xù)使用我們的老例子,將一個累加的過程分成兩個進程奇徒,這里我就不對案例的過程詳細(xì)介紹了雏亚,如果沒看懂的先出門看一下我前面的兩篇文章:http://www.reibang.com/p/31bca20caec0和http://www.reibang.com/p/e7a5f3b2afcf。這里我主要介紹一下和之前不同的地方摩钙,這里是有返回值的罢低,我們在上面的程序中使用 part_result = []來存儲我們建立的進程,后面我們在使用for循環(huán)遍歷這個存儲進程的列表胖笛,使用get()方法得到進程的結(jié)果并將其累加网持。我們來看一些結(jié)果:
第0個進程的結(jié)果為125000000250000000
第1個進程的結(jié)果為375000000250000000
結(jié)果為 500000000500000000
0:00:34.825516
上面的例子中我們使用了Pool來對有返回的進程距離一個例子宜岛,但是這里使用了get()來收集進程的返回值,下面我們來使用map()方法來直接收集進程返回的結(jié)果功舀,上代碼:
def add_part(part):
"""計算一個列表的開始到末尾的累加
:param part:長度為二的列表
:return: 返回累加的和
"""
result = 0
for value in range(part[0], part[1] + 1):
result += value
return result
if __name__ == '__main__':
# 第二種方式使用pool.map(),直接獲取所有進程的結(jié)果獲取結(jié)果
startTime = datetime.datetime.now()
pool = Pool(processes=2)
part_result = (pool.map(add_part, [[0, 500000000], [500000001, 1000000000]]))
pool.close()
pool.join()
print(part_result)
add_result = 0
for i in part_result:
print(i)
add_result += i
print("結(jié)果為:", add_result)
print(datetime.datetime.now() - startTime)
運行結(jié)果為:
[125000000250000000, 375000000250000000]
125000000250000000
375000000250000000
結(jié)果為: 500000000500000000
0:00:32.576957
我們來看一下上面的代碼萍倡,我們使用了map()方法直接將進程的結(jié)果輸出到part_result 列表中。下一篇文章中我們繼續(xù)介紹多個線程之間的數(shù)據(jù)交互日杈。