【示例-多任務】Python 協程gevent模塊

協程,又稱微線程,纖程。協程是Python中另外一種實現多任務的方式, 是比線程佔用更小的執行單元。
多進程, 多線程, 協程中差異見: 【Python面試場景】進程-線程-協程相關問題彙總

gevent是一個強大的並且能夠自動切換任務的模塊, 是Python的第三方庫, 需要單獨安裝。它使用 greenlet在libev 或libuv事件循環的頂部提供高級同步API 。

pip3 install gevent

其原理是當一個greenlet遇到IO(指的是input output 輸入輸出,比如網絡、文件操作等)操作時,比如訪問網絡,就自動切換到其他的greenlet,等到IO操作完成,再在適當的時候切換回來繼續執行。

由於IO操作非常耗時,經常使程序處於等待狀態,有了gevent爲我們自動切換協程,就保證總有greenlet在運行,而不是等待IO

1 使用

該案例中並沒有切換執行

import gevent

def f(n):
    for i in range(n):
        print(gevent.getcurrent(), i)

g1 = gevent.spawn(f, 5)
g2 = gevent.spawn(f, 5)
g3 = gevent.spawn(f, 5)
g1.join()
g2.join()
g3.join()

2 切換執行

import gevent

def f(n):
    for i in range(n):
        print(gevent.getcurrent(), i)
        #用來模擬一個耗時操作,注意不是time模塊中的sleep
        gevent.sleep(1)

g1 = gevent.spawn(f, 5)
g2 = gevent.spawn(f, 5)
g3 = gevent.spawn(f, 5)
g1.join()
g2.join()
g3.join()

3 打補丁 Monkey

from gevent import monkey
import gevent
import random
import time

# 有耗時操作時需要
monkey.patch_all()  # 將程序中用到的耗時操作的代碼,換爲gevent中自己實現的模塊

def coroutine_work(coroutine_name):
    for i in range(10):
        print(coroutine_name, i)
        time.sleep(random.random())

gevent.joinall([
        gevent.spawn(coroutine_work, "work1"),
        gevent.spawn(coroutine_work, "work2")
])

4 【多任務案例】併發下載器

from gevent import monkey
import gevent
import urllib.request

#有IO才做時需要這一句
monkey.patch_all()

def my_downLoad(file_name, url):
    print('GET: %s' % url)
    resp = urllib.request.urlopen(url)
    data = resp.read()

    with open(file_name, "wb") as f:
        f.write(data)

    print('%d bytes received from %s.' % (len(data), url))

gevent.joinall([
        gevent.spawn(my_downLoad, "1.mp4", 'http://***.***.com/***.mp4'),
        gevent.spawn(my_downLoad, "2.mp4", 'http://***.***.com/***.mp4'),
])

更多官方案例 https://github.com/gevent/gevent/blob/master/examples/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章