日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

day36 python学习gevent io 多路复用 socketserver *****

發布時間:2024/1/17 python 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 day36 python学习gevent io 多路复用 socketserver ***** 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

---恢復內容開始---

gevent

1、切換+保存狀態
2、檢測單線程下任務的IO,實現遇到IO自動切換

?

Gevent 是一個第三方庫,可以輕松通過gevent實現并發同步或異步編程,在gevent中用到的主要模式是Greenlet, 它是以C擴展模塊形式接入Python的輕量級協程。 Greenlet全部運行在主程序操作系統進程的內部,但它們被協作式地調度。

?

#用法 g1=gevent.spawn(func,1,,2,3,x=4,y=5)創建一個協程對象g1,spawn括號內第一個參數是函數名,如eat,后面可以有多個參數
,可以是位置實參或關鍵字實參,都是傳給函數eat的g2=gevent.spawn(func2)g1.join() #等待g1結束g2.join() #等待g2結束#或者上述兩步合作一步:gevent.joinall([g1,g2])g1.value#拿到func1的返回值

遇到IO阻塞時會自動切換任務

#初識gevent import gevent def task():print('aaa')gevent.sleep(3)# 當遇到io 時 不會等,會切到task1,然后執行task1的代碼,然后又遇到IC再切回來#回來一看還在睡,然后再切到task1 來回切直到有一個睡醒了就行了print('cccc') def task1():print('aaa')gevent.sleep(2)print('cccc')t1=gevent.spawn(task,) t2=gevent.spawn(task1,) t1.join() t2.join() print('zhu')

上例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()放到文件的開頭

from gevent import monkey,spawn;monkey.patch_all() #這個模塊的引入一定要放在最上邊 #因為socket from socket import * import time #from threading import Thread def server(ip,cont):server=socket(AF_INET,SOCK_STREAM)server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)server.bind((ip,cont))server.listen(5)while True:print('aaa')time.sleep(0.1)print('bbb')conn,addr=server.accept()# 因為接受的過程中會有IO# (即是accept 在等 wait data 和data copy這兩個過程)#然后就會去切到task 函數 task 函數如果沒有內容就會切回來來回切換#這樣減少了等待,提高了效率,(相當與單線程下實現并發)spawn(task,conn,) # 實現了單線程下的并發,因為這里是新開了一個函數# 而不是新開了一個線程或者進程,所以這樣弄節省內存空間 def task(conn):while True:print('ccc')try:data=conn.recv(1024)if not data:continueconn.send(data.upper())except ConnectionResetError:conn.close()if __name__ == '__main__':server('127.0.0.1',8090) #1 對cpu的占用率過多,但是是無用的占用 #2 在連接數過多的情況下,不能及時響應客戶的的消息 from socket import * import time server=socket(AF_INET,SOCK_STREAM) server.bind(('127.0.0.1',8090)) server.listen(5) server.setblocking(False)#設置為 conn_l=[] #將conn 加到列表中,讓下一列用 while True:try:conn,addr=server.accept()conn_l.append(conn)print(addr)except BlockingIOError:print('去干其他活兒了',len(conn_l))del_l=[]for conn in conn_l: #在這里用例表中存入的內容try:data=conn.recv(1024)if not data:del_l.append(data) #如果是空的放到問題項列表中,continueconn.send(data.upper())except BlockingIOError:passexcept ConnectionResetError:conn.close() #關閉conn del_l.append(conn)for i in del_l:conn_l.remove(i) #刪除有問題的內容。 非阻塞IO模型

?

socketserver模塊

import socketserver class MyTCPHandler(socketserver.BaseRequestHandler):#定義一個類繼承他得使用他的規則def handle(self): #處理通信的活兒print('=====>',self)#self.request==conn 他們兩個是等價的意思print(self.request) #打印的內容為<socket.socket fd=452, family=AddressFamily.AF_INET,# type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8080),# raddr=('127.0.0.1', 63347)> 他是套接字對象,等價于conn 包含recv方法while True:data=self.request.recv(1024)self.request.send(data.upper())if __name__ == '__main__':# socketserver.ForkingTCPServer linux的用這個server=socketserver.ThreadingTCPServer(('127.0.0.1',8080),MyTCPHandler)server.serve_forever()#以上的代碼等價于如下的操作,建立連接,相當于把他封裝在了這個對象中# while True:# conn,addr=server.accept()# t=Thread(target=func,args=(conn,))# t.start()

?SocketServer 模塊 ?重要*****

SocketServer內部使用 IO多路復用 以及 “多線程”“多進程” ,從而實現并發處理多個客戶端請求的Socket服務端

#tcp 服務端
import
socketserver class MyTCPHandler(socketserver.BaseRequestHandler):#定義一個類繼承他得使用他的規則def handle(self): #處理通信的活兒print('=====>',self)#self.request==conn 他們兩個是等價的意思print(self.request) #打印的內容為<socket.socket fd=452, family=AddressFamily.AF_INET,# type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8080),# raddr=('127.0.0.1', 63347)> 他是客戶端的套接字對象,等價于conn# 包含recv方法while True:data=self.request.recv(1024)self.request.send(data.upper())if __name__ == '__main__':# socketserver.ForkingTCPServer linux的用這個server=socketserver.ThreadingTCPServer(('127.0.0.1',8080),MyTCPHandler)#??server.serve_forever() #循環的建鏈接,#以上的代碼等價于如下的操作,建立連接,相當于把他封裝在了這個對象中# while True:# conn,addr=server.accept()# t=Thread(target=func,args=(conn,))# t.start()

?

#UDP服務端
import
socketserver class MyUDPhandler(socketserver.BaseRequestHandler):def handle(self):print(self.request)#(b'ss', <socket.socket fd=408,# family=AddressFamily.AF_INET, type=SocketKind.SOCK_DGRAM,# proto=0, laddr=('127.0.0.1', 8080)>)#打印出來的是一個元祖, 第一個值是收到客戶端發送的信號,第二個值是#服務端---套接字對象client_data=self.request[0] #cclient_data 這個格式是固定的,不要改變它self.request[1].sendto(client_data.upper(),self.client_address)#client_address 這個是他自己有的 if __name__ == '__main__':server=socketserver.ThreadingUDPServer(('127.0.0.1',8080),MyUDPhandler)server.serve_forever()

?

I/O多路復用
Linux中的?select,poll,epoll 都是IO多路復用的機制。I/O多路復用指:通過一種機制,可以監視多個描述符

一旦某個描述符就緒(一般是讀就緒或者寫就緒),能夠通知程序進行相應的讀寫操作。

#select 的功能只是監測套接字有沒有數據,不負責取 from socket import * import time import select server=socket(AF_INET,SOCK_STREAM) server.bind(('127.0.0.1',8090)) server.listen(5) server.setblocking(False)#設置為 read_l=[server,] #初始狀態加server, 初始狀態要對這個套接字對象進行監控, # 當不阻塞時(即有客戶端連過來的)select while True:r1,w1,x1=select.select(read_l,[],[])##read_l=[server,conn1,conn2,conn3]# 里邊要傳入三個參數,# 當要用那個的時候傳入對應的列表,要監控讀時要在第一個# 不用的傳入空列表#r1[]列表中只寸準備好的套接字#print(r1[0] is server)# r1[0]是一個套接字對象 服務端for r in r1:#循環列表,將里邊準備好的內容執行,實現并發的效果if r is server: #判斷好了的對象是 server 還是connconn,addr=r[0].accept()print(addr)read_l.append(conn)else: #如果是conn就執行這些代碼try:data=r.recv(1024)if not data:r.close()read_l.remove(r)r.send(data.upper())except ConnectionResetError:r.close()read_l.remove(r)

?

?

?

 

轉載于:https://www.cnblogs.com/wangkun122/p/7994487.html

總結

以上是生活随笔為你收集整理的day36 python学习gevent io 多路复用 socketserver *****的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。