python-day35(協程,IO多路複用)
阿新 • • 發佈:2018-12-04
一. 協程
協程: 是單執行緒下的併發,又稱微執行緒,纖程,英文名Coroutine.
併發: 切換+儲存狀態
協程是一種使用者態的輕量級執行緒,即協程是由使用者程式自己控制排程的
協程特點:
1. 必須在只有一個單執行緒裡實現併發
2. 修改共享資料不需要加鎖
3. 使用者程式自己儲存多個控制流的上線文棧
4. 一個協程遇到IO操作自動切換到其他協程(如何實現檢測IO,yield,greenlet都無法實現,
就用到了gevent模組(select機制))
Greenlet模組
單純的切換(在沒有IO的情況下或者沒有重複開闢記憶體空間的操作),反而會降低程式的執行速度
#真正的協程模組就是使用greenlet完成的切換 from greenlet import greenlet def eat(name): print('%s eat 1' %name) #2 g2.switch('taibai') #3 print('%s eat 2' %name) #6 g2.switch() #7 def play(name): print('%s play 1' %name) #4 g1.switch() #5 print('%s play 2' %name) #8 g1=greenlet(eat) g2=greenlet(play) g1.switch('taibai')#可以在第一次switch時傳入引數,以後都不需要 1
#安裝 pip install greenlet
1 # import time 2 # 3 # import greenlet 4 # def fun1(): 5 # time.sleep(2) 6 # print('約嗎?') 7 # g2.switch() 8 # time.sleep(2) 9 # print('不約') 10 # g2.switch() 11greenlet練習# def fun2(): 12 # time.sleep(2) 13 # print('你好') 14 # g1.switch() 15 # time.sleep(2) 16 # print('你不好') 17 # 18 # g1 = greenlet.greenlet(fun1) 19 # g2 = greenlet.greenlet(fun2) 20 # g1.switch() 21 # ---------------------------------------------------- 22 # import time 23 # import greenlet 24 # def f1(name): 25 # print(name) 26 # time.sleep(2) 27 # a = g2.switch(name+'1') 28 # print(a) 29 # 30 # def f2(name): 31 # print(name) 32 # time.sleep(2) 33 # g1.switch(name+'1') 34 # 35 # a = time.time() 36 # g1 = greenlet.greenlet(f1) 37 # g2 = greenlet.greenlet(f2) 38 # g1.switch('hui') 39 # b = time.time() 40 # print(b-a)
Gevent模組
#安裝 pip install gevent
#用法 g1 = gevent.spawn(func,多個引數) 建立一個協程物件g1, spawn(函式名,多個引數) spawn是非同步提交任務 g2 = gevent.spawn(func2) g1.join() #等待g1結束,上面只是建立協程物件,這個join才是去執行
g2.join() #等待g2結束,
gevent.joinall([g1,g2]) #等待列表中的協程都結束
g1.value #拿到func1的返回值
gevent.sleep(2)# 睡2秒 遇到IO切換
# 不能識別time.sleep 解決辦法 from gevent import monkey;monkey.patch_all()
遇到IO阻塞是自動切換任務
import gevent def eat(name): print('%s eat 1' %name) gevent.sleep(2) print('%s eat 2' %name) def play(name): print('%s play 1' %name) gevent.sleep(1) print('%s play 2' %name) g1=gevent.spawn(eat,'egon') g2=gevent.spawn(play,name='egon') g1.join() g2.join() #或者gevent.joinall([g1,g2]) print('主')
gevent.sleep(2)模擬的是gevent可以識別的io阻塞,
而time.sleep(2)或其他的阻塞,gevent是不能直接識別的需要下面一行的程式碼,打補丁,就可以識別
from gevent import monkey;monkey.patch_all()必須放到被打補丁者的前面,如time,socket模組之前
或者直接記憶成: 要用gevent, 需要將from gevent import monkey;monkey.patch_all()放到檔案的開頭
1 # import gevent 2 # import time 3 # #gevent 不能識別 time.sleep 4 # # 解決辦法 from gevent import monkey;monkey.patch_all() 識別所有的IO 自動切換 5 # 6 # def func(n,): 7 # print('xxxx',n) 8 # gevent.sleep(2) 9 # # time.sleep(2) #不能識別 10 # print('ccccc') 11 # 12 # def func2(m): 13 # print('11111111',m) 14 # gevent.sleep(2) 15 # print('22222222') 16 # g1 = gevent.spawn(func,'alex') # 非同步提交任務 17 # g2 = gevent.spawn(func2,'馬來西亞') 18 # 19 # # gevent.joinall([g1,g2]) #等多所有 20 # g1.join() #執行並等待非同步提交的任務完成 21 # g2.join()#執行並等待非同步提交的任務完成 22 # print('程式碼結束')from gevent import monkey;monkey.patch_all()
二. IO多路複用
IO模型
#1) 等待資料準備(Waiting for the data to be ready) #2) 將資料從核心拷貝到程序中(Copying the data from the kernel to the process)
1. 阻塞IO
2. 非阻塞IO模型
3. IO多路複用
4. 非同步IO