協程(corouutine):輕量級的線程,不存在上下文切換,能在多個任務之間排程的多任務方式,可以使用,yield實作
線程和程序的操作是由程式觸發系統接口,最後的執行者是系統,它本質上是作業系統提供的功能。而協程的操作則是程式員指定的,在python中通過yield,人為的實作并發處理。
協程存在的意義:對于多線程應用,CPU通過切片的方式來切換線程間的執行,線程切換時需要耗時。協程,則隻使用一個線程,分解一個線程成為多個“微線程”,在一個線程中規定某個代碼塊的執行順序。
協程的适用場景:當程式中存在大量不需要CPU的操作時(IO)。
簡單多任務協程實列:
import time
import threading
def task_1():
print(threading.current_thread())
while True:
print('---1---')
time.sleep(1)
yield
def task_2():
print(threading.current_thread())
while True:
print('---2---')
time.sleep(1)
yield
def main():
t1=task_1()
t2=task_2()
while True:
next(t1)
next(t2)
if __name__ == '__main__':
main()
在不需要自己“造輪子”的年代,同樣有第三方子產品為我們提供了高效的協程,這裡介紹一下greenlet和gevent。本質上,gevent是對greenlet的進階封裝,是以一般用它就行,這是一個相當高效的子產品。
在使用它們之前,需要先安裝,可以通過源碼,也可以通過pip。
greenlet
def test1():
print(12)
gr2.switch()
print(34)
gr2.switch()
def test2():
print(56)
gr1.switch()
print(78)
gr1 = greenlet(test1)
gr2 = greenlet(test2)
gr1.switch()
gevent
from gevent import monkey; monkey.patch_all()
import gevent
import requests
def f(url):
print('GET: %s' % url)
resp = requests.get(url)
data = resp.text
print('%d bytes received from %s.' % (len(data), url))
gevent.joinall([
gevent.spawn(f, 'https://www.python.org/'),
gevent.spawn(f, 'https://www.yahoo.com/'),
gevent.spawn(f, 'https://github.com/'),
])