进程池和线程池
我們知道多進程可以利用多核CPU進行并行計算,但多進程的資源開銷很大,因此不可能無限開。舉個栗子,假設有100塊磚,是請5個人去搬,還是請100個人去搬?答案是5個人,100個人工錢太貴了。。。這就和開多進程是一樣的道理。那如何限制進程數量呢?通過進程池。
Pool可以提供指定數量的進程,供用戶調用,當有新的請求提交到pool中時,如果池還沒有滿,那么就會創建一個新的進程用來執行該請求;但如果池中的進程數已經達到規定最大值,那么該請求就會等待,直到池中有進程結束,就重用進程池中的進程。
from multiprocessing import Pool import os, timedef foo(i):print('進程【%s】,id-->%s'%(i,os.getpid()))time.sleep(2)if __name__ == '__main__':pool = Pool(4) # 指定進程池大小,默認為CPU核心數for i in range(1,10):pool.apply_async(func=foo, args=(i,)) # 如果沒有返回計算結果就不用賦值pool.close() # 關閉進程池pool.join() # 等待進程池內任務處理完,否則主進程走完就結束了進程池的方法:
pool = Pool() 創建進程池
pool.apply(func=func_name, args=()) 從進程池里取一個進程并執行
pool.apply_async(func=func_name, args=()) apply的異步版本
apply() 和apply_async的返回值是結果對象obj, 通過obj.get()可以收集結果。
pool.close() 關閉進程池
pool.terminate() 終止所有工作進程
pool.join() 主進程等待所有子進程執行完畢,必須在close或terminate之后
Python3 中的進程池和線程池
python3中針對進程池和線程池提供了更易用的接口。使用方式也是一樣的:
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor # 導入 import random, timedef get_html(url):print('請求%s' % url)time.sleep(random.randint(1, 3))return '%s html......' % urldef parse_html(res):html = res.result() # 任務完成返回的是結果對象,回調函數接收該對象通過.result()獲取真實結果print(html)if __name__ == "__main__":start = time.time()pool = ProcessPoolExecutor(4) # 默認進程池大小等于CPU核心數# pool = ThreadPoolExecutor(6) # 線程池一般20-30左右足夠,可以根據任務適當調整urls = ['url_1', 'url_2', 'url_3', 'url_4', 'url_5', 'url_6']for url in urls:pool.submit(get_html, url).add_done_callback(parse_html) # 提交任務到進程池并指定回調函數,即子進程執行結果出來后,通知主進程處理結果(執行回調函數)pool.shutdown(wait=True) # 關閉進程等待任務結束;這里主要是為了阻塞主進程,統計時間用end = time.time()print('一共耗時:', end - start)"""請求url_1請求url_2請求url_3請求url_4請求url_5url_1 html......請求url_6url_4 html......url_6 html......url_5 html......url_2 html......url_3 html......一共耗時: 3.2524783611297607"""可以看到,如果要用線程,只需要實例化線程池對象即可。使用非常方便。
總結
- 上一篇: Django(四)数据库
- 下一篇: 预处理器指令