一、協(xié)程
- 并發(fā):同一時間段內(nèi),多個任務(wù)執(zhí)行(單核CPU可以實現(xiàn))。
- 并行:同一時刻虱饿,多個任務(wù)執(zhí)行(只能多核)
協(xié)程是程序員臆想出來的單線程實現(xiàn)并發(fā),在應(yīng)用程序里控制多個任務(wù)的切換+保存狀態(tài)触趴。
yield:生成器氮发,只要函數(shù)中有yield關(guān)鍵字,這個函數(shù)就是生成器冗懦,通過yield可以實現(xiàn)保存狀態(tài)+切換
- 協(xié)程的優(yōu)點:協(xié)程的切換開銷更小爽冕,屬于程序級別的切換,操作系統(tǒng)完全感知不到披蕉,因而更加輕量級颈畸;單線程內(nèi)就可以實現(xiàn)并發(fā)的效果,最大限度地利用cpu没讲。
- 協(xié)程的缺點:多個任務(wù)一旦有一個阻塞沒有切眯娱,整個線程都阻塞在原地
該線程內(nèi)的其他的任務(wù)都不能執(zhí)行了。
一旦引入?yún)f(xié)程爬凑,就需要檢測單線程下所有的IO行為,實現(xiàn)遇到IO就切換,少一個都不行徙缴,以為一旦一個任務(wù)阻塞了,整個線程就阻塞了嘁信,其他的任務(wù)即便是可以計算娜搂,但是也無法運(yùn)行了迁霎。
二吱抚、greenlet模塊
greenlet模塊遇到IO不會切換
from greenlet import greenlet
import time
# 遇到io不會切百宇,初級模塊,gevent模塊基于它寫的秘豹,處理io切換
def eat():
print('我吃了一口')
p.switch()
print('我又吃了一口')
p.switch()
def play():
print('我玩了一會')
e.switch()
print('我又玩了一會')
if __name__ == '__main__':
e = greenlet(eat)
p = greenlet(play)
e.switch()
三携御、gevent模塊
使用gevent庫需要先安裝:
#安裝
pip3 install gevent
Gevent 是一個第三方庫,可以輕松通過gevent實現(xiàn)并發(fā)同步或異步編程既绕,在gevent中用到的主要模式是Greenlet, 它是以C擴(kuò)展模塊形式接入Python的輕量級協(xié)程啄刹。 Greenlet全部運(yùn)行在主程序操作系統(tǒng)進(jìn)程的內(nèi)部,但它們被協(xié)作式地調(diào)度凄贩。
用法
import gevent
import time
def eat(name):
print('%s 吃了一口' % name)
gevent.sleep(1)
print('%s 又吃了一口' % name)
def play(name):
print('%s 玩了一會' % name)
gevent.sleep(2)
print('%s 又玩了一會' % name)
if __name__ == '__main__':
ctim = time.time()
e = gevent.spawn(eat,'lqz')
p = gevent.spawn(play,'lqz')
e.join() # 等待e執(zhí)行完成
p.join()
print('主')
print(time.time() - ctim) #2.0165154933929443
四誓军、asyncio
# 官方支持協(xié)程的庫
# import time
# import asyncio
#
# # 把普通函數(shù)變成協(xié)程函數(shù)
# # 3.5以前這么寫
# @asyncio.coroutine
# def task():
# print('開始了')
# yield from asyncio.sleep(1) #asyncio.sleep(1)模擬io
# print('結(jié)束了')
#
#
# loop=asyncio.get_event_loop() # 獲取一個時間循環(huán)對象#
#
# # 協(xié)程函數(shù)加括號,并不會真正的去執(zhí)行疲扎,它需要提交給loop昵时,讓loop循環(huán)著去執(zhí)行
# # 協(xié)程函數(shù)列表
#
# ctime=time.time()
# t=[task(),task()]
# loop.run_until_complete(asyncio.wait(t))
# loop.close()
# print(time.time()-ctime)
import time
import asyncio
from threading import current_thread
# 表示我是協(xié)程函數(shù),等同于3.5之前的裝飾器
async def task():
print('開始了')
print(current_thread().name)
await asyncio.sleep(3) # await等同于原來的yield from
print('結(jié)束了')
async def task2():
print('開始了')
print(current_thread().name)
await asyncio.sleep(2)
print('結(jié)束了')
loop=asyncio.get_event_loop()
ctime=time.time()
t=[task(),task2()]
loop.run_until_complete(asyncio.wait(t))
loop.close()
print(time.time()-ctime)