python 之gevent 協程操作


gevent的簡介

  gevent是一個基於協程的python網絡庫,在遇到IO阻塞時,程序會自動進行切換,可以讓我們用同步的方式寫異步IO代碼。

    因為python線程的性能問題,在python中使用多線程運行代碼經常不能達到預期的效果。而有些時候我們的邏輯中又需要開更高的並發,或者簡單的說,就是讓我們的代碼跑的更快,在同樣時間內執行更多的有效邏輯、減少無用的等待。gevent就是一個現在很火、支持也很全面的python第三方協程庫。
    gevent是python的一個並發框架,以微線程greenlet為核心,使用了epoll事件監聽機制以及諸多其他優化而變得高效。而且其中有個monkey類,將現有基於Python線程直接轉化為greenlet(類似於打patch)。在運行時的具體流程大概就是:
    當一個greenlet遇到IO操作時,比如訪問網絡/睡眠等待,就自動切換到其他的greenlet,等到IO操作完成,再在適當的時候切換回來繼續執行。由於IO操作非常耗時,經常使程序處於等待狀態,有了gevent為我們自動切換協程,就保證總有greenlet在運行,而不是等待IO。同時也因為只有一個線程在執行,會極大的減少上下文切換的成本。
 

gevent基本使用 不加gevent.monkey是順序執行起不到協程的作用

 

# -*- coding: utf-8 -*-

import gevent

def f1():
    for i in range(5):
        print 'run func: f1, index: %s ' % i
        gevent.sleep(0)


def f2():
    for i in range(5):
        print 'run func: f2, index: %s ' % i
        gevent.sleep(0)


t1 = gevent.spawn(f1)
t2 = gevent.spawn(f2)
gevent.joinall([t1, t2])

 

運行后輸出如下圖所示是順序執行,並沒有切換:

 

gevent的正確使用

import gevent
import gevent.pool
import gevent.monkey

gevent.monkey.patch_all()  # 分布式沖突
import requests


def download_img(t_event_data):
    """
    保存圖片到本地
    :return:
    """
    try:
        index = t_event_data["index"]
        num = t_event_data["num"]
        r = requests.get("https://wwww.baidu.com")
        print("index:{} num:{}".format(index, num))

    except Exception as e:
        print("下載異常:{}".format(e))


def main():
    try:
        num_list = [i for i in range(1, 100)]  # 相當於起了100個協程池
        gevent_data_list = []

        for index, num in enumerate(num_list):
            t_event_data = {}
            t_event_data["index"] = index
            t_event_data["num"] = num
            gevent_data_list.append(gevent.spawn(download_img, t_event_data))

        gevent.joinall(gevent_data_list)
    except Exception as e:
        print("異常 {}".format(e))


if __name__ == "__main__":
    main()

 

gevent 協程池的使用

協程池相對要好用些,可以自定義一個協程池指定個數,把待執行的隊列(列表)丟進去,即可執行

import gevent
import gevent.pool
import gevent.monkey

gevent.monkey.patch_all()  # 分布式沖突
import requests


def download_img(t_event_data):
    """
    保存圖片到本地
    :return:
    """
    try:
        index = t_event_data["index"]
        num = t_event_data["num"]
        r = requests.get("https://wwww.baidu.com")
        print("index:{} num:{}".format(index, num))

    except Exception as e:
        print("下載異常:{}".format(e))


def main():
    try:
        num_list = [i for i in range(1, 100)] #待處理的數據
        gevent_data_list = []

        mypool = gevent.pool.Pool(10)  # 定義協程池個數

        for index, num in enumerate(num_list):
            t_event_data = {}
            t_event_data["index"] = index
            t_event_data["num"] = num
            gevent_data_list.append(t_event_data)
        result = mypool.map(download_img, gevent_data_list)
        print(result)
    except Exception as e:
        print("異常 {}".format(e))


if __name__ == "__main__":
    main()

 

 

 

 


免責聲明!

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



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