Python Django 協程報錯,進程池、線程池與異步調用、回調機制


一、問題描述

在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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM