协程,IO模式
1、協程(別人的模塊,達到單線程并發效果)
程序的運行狀態:
阻塞:
IO阻塞
非阻塞:
運行
就緒
單線程實現并發:
在應用程序里控制多個任務的切換+保存狀態
可以把IO減下來,但是不可能降到無
優點:
應用程序級別速度要遠遠高于操作系統的切換
缺點:
多個任務一旦有一個阻塞沒有切,整個縣城都堵塞在原地
該線程內的其他的任務都不能執行
?
一旦引入協程,就需要檢測單線程下素有的IO行為,
實現遇到IO就切換,少一個都不行,因為一旦一個任務阻塞,整個線程就 阻塞,其他的任務即便是可以計算,但是也無法運行。
2、用協程的目的
想要在單線程下實現并發
并發指的是多個任務看起來是同時運行的
并發=切換+保存狀態
線程在進程內,進程在操作系統內,一切由操作系統控制
?
自己設置python程序讓線程形成切換,不用操作系統控制。
協程只有單線程下遇到IO切換才會提成效率,操作系統相對與協程要更慢點
?
import timedef func1():for i in range(1000000):i+1 def func2():for i in range(1000000):i+1 start = time.time() func1() func2() stop=time.time() print(stop-start)# 基于yield并發 import time def func1():while True:print("func1")yield def func2():g=func1()for i in range(1000000):print("func2")i+1time.sleep(3)next(g)start=time.time() func2() stop=time.time() print(stop-start) 串行執行:?
from gevent import monkey,spawn;monkey.patch_all()#monkey.patch_all()補丁 import timedef eat(name):print("%s eat 1" %name)time.sleep(3)print("%s eat 2" %name) def play(name):print("%s play 1" %name)time.sleep(1)print("%s play 2" %name)start=time.time() g1=spawn(eat,"yf")#自動運行任務 模塊 g2=spawn(play,"fxc")g1.join()#通過補丁讓join識別其他IO g2.join() print(time.time() - start) print(g1) print(g2)from gevent import monkey,spawn;monkey.patch_all() from threading import current_thread import timedef eat(name):print("%s eat 1" %current_thread().name)#都是一個線程,前面有dummy假標明time.sleep(3)print("%s eat 2" %current_thread().name) def play(name):print("%s play 1" %current_thread().name)time.sleep(1)print("%s play 2" %current_thread().name)start=time.time() g1=spawn(eat,"yf") g2=spawn(play,"fxc")g1.join() g2.join() print(time.time() - start) print(g1) print(g2) 與yield類似可以直接計算的 gevent并發的套接字通信:
from gevent import spawn,monkey;monkey.patch_all() from socket import * from threading import Threaddef talk(conn):while True:try:data = conn.recv(1024)if len(data)==0:breakconn.send(data.upper())except ConnectionResetError:breakconn.close()def server(ip,port,backlog=5):server = socket(AF_INET,SOCK_STREAM)server.bind((ip,port))server.listen(backlog)print("starting..")while True:conn,addr=server.accept()spawn(talk,conn) if __name__ == '__main__':g=spawn(server,"127.0.0.1",8080)g.join() 服務器: from threading import Thread,current_thread from socket import *def task():client = socket(AF_INET,SOCK_STREAM)client.connect(("127.0.0.1",8080))while True:msg="%s say hello" %current_thread().nameclient.send(msg.encode("utf-8"))data=client.recv(1024)print(data.decode("utf-8"))if __name__ == '__main__':for i in range(500):t=Thread(target=task)t.start() 客戶端:網絡IO:
????recvfrom:#等待客戶鏈接請求
????????wait data:等待客戶端產生數據——》客戶端OS--》網絡--》服務端操作系統緩存
????????copy data:由本地操作系統緩存中的數據拷貝到應用程序的內存中
?
????send:
????????copy data
conn.recv(1024) ==>OS
from socket import * import timeserver = socket() server.bind(("127.0.0.1",8080)) server.listen(5) server.setblocking(False)#是否有鏈接過來 conn_l=[] while True:try:print("總連接數[%s]" %len(conn_l))conn,addr=server.accept()conn_l.append(conn)except BlockingIOError:del_l=[]for conn in conn_l:try:data=conn.recv(1024)if len(data)==0:del_l.append(conn)continueconn.send(data.upper())except BlockingIOError:passexcept ConnectionResetError:del_l.append(conn)for conn in del_l:conn_l.remove(conn) 服務端: from socket import * import osclient=socket(AF_INET,SOCK_STREAM) client.connect(("127.0.0.1",8080)) while True:msg="%s say hello" %os.getpid()client.send(msg.encode("utf-8"))data=client.recv(1024)print(data.dacoda("utf-8")) 客戶端:?
轉載于:https://www.cnblogs.com/yf18767106368/p/9325944.html
總結
- 上一篇: 唐宇迪学习笔记9:逻辑回归与梯度下降策略
- 下一篇: nuxt中必须要知道的一点 关于 nux