一、問題描述
在Django視圖函數中,導入 gevent 模塊
import gevent from gevent import monkey; monkey.patch_all() from gevent.pool import Pool
啟動Django報錯:
MonkeyPatchWarning: Monkey-patching outside the main native thread. Some APIs will not be available. Expect a KeyError to be printed at shutdown. from gevent import monkey; monkey.patch_all() MonkeyPatchWarning: Monkey-patching not on the main thread; threading.main_thread().join() will hang from a greenlet from gevent import monkey; monkey.patch_all()
原因在於執行這行 monkey.patch_all() 代碼時報錯了。
既然Django不能使用協程,那我需要使用異步執行,怎么辦?
請看下文
二、進程池、線程池與異步調用、回調機制
進程池、線程池使用案例
進程池與線程池使用幾乎相同,只是調用模塊不同~!!
from concurrent.futures import ProcessPoolExecutor # 進程池模塊 from concurrent.futures import ThreadPoolExecutor # 線程池模塊 import os, time, random # 下面是以進程池為例, 線程池只是模塊改一下即可 def talk(name): print('name: %s pis%s run' % (name,os.getpid())) time.sleep(random.randint(1, 3)) if __name__ == '__main__': pool = ProcessPoolExecutor(4) # 設置線程池大小,默認等於cpu核數 for i in range(10): pool.submit(talk, '進程%s' % i) # 異步提交(只是提交需要運行的線程不等待) # 作用1:關閉進程池入口不能再提交了 作用2:相當於jion 等待進程池全部運行完畢 pool.shutdown(wait=True) print('主進程')
異步調用與同步調用
concurrent.futures模塊提供了高度封裝的異步調用接口
ThreadPoolExecutor:線程池,提供異步調用
ProcessPoolExecutor: 進程池,提供異步調用
同步調用
from concurrent.futures import ProcessPoolExecutor # 進程池模塊 import os, time, random # 1、同步調用: 提交完任務后、就原地等待任務執行完畢,拿到結果,再執行下一行代碼(導致程序串行執行) def talk(name): print('name: %s pis%s run' % (name,os.getpid())) time.sleep(random.randint(1, 3)) if __name__ == '__main__': pool = ProcessPoolExecutor(4) for i in range(10): pool.submit(talk, '進程%s' % i).result() # 同步迪奧用,result(),相當於join 串行 pool.shutdown(wait=True) print('主進程')
異步調用
from concurrent.futures import ProcessPoolExecutor # 進程池模塊 import os, time, random def talk(name): print('name: %s pis%s run' % (name,os.getpid())) time.sleep(random.randint(1, 3)) if __name__ == '__main__': pool = ProcessPoolExecutor(4) for i in range(10): pool.submit(talk, '進程%s' % i) # 異步調用,不需要等待 pool.shutdown(wait=True) print('主進程')
回調機制
可以為進程池或線程池內的每個進程或線程綁定一個函數,該函數在進程或線程的任務執行完畢后自動觸發,並接收任務的返回值當作參數,該函數稱為回調函數
#parse_page拿到的是一個future對象obj,需要用obj.result()拿到結果 p.submit(這里異步調用).add_done_callback(方法)
案例:下載解析網頁頁面
import time import requests from concurrent.futures import ThreadPoolExecutor # 線程池模塊 def get(url): print('GET %s' % url) response = requests.get(url) # 下載頁面 time.sleep(3) # 模擬網絡延時 return {'url': url, 'content': response.text} # 頁面地址和頁面內容 def parse(res): res = res.result() # !取到res結果 【回調函數】帶參數需要這樣 print('%s res is %s' % (res['url'], len(res['content']))) if __name__ == '__main__': urls = { 'http://www.baidu.com', 'http://www.360.com', 'http://www.iqiyi.com' } pool = ThreadPoolExecutor(2) for i in urls: pool.submit(get, i).add_done_callback(parse) # 【回調函數】執行完線程后,跟一個函數
本文參考鏈接:
https://blog.csdn.net/weixin_42329277/article/details/80741589