Python多路復用selector模組的基本使用

2022-09-24 14:36:15 字數 2750 閱讀 2721

目錄

o多路復用技術是使用乙個可以同時監視多個io阻塞的中間人去監視這些不同的io物件,這些被監視的任何乙個或多個io物件有訊息返回,都將會觸發這個中間人將這些有訊息io物件返回,以供獲取他們的訊息。

使用io多路復用的優點在於,程序在單執行緒的情況下同樣可以同時處理多個io阻塞。與傳統的多執行緒/多程序模型比,i/o多路復用系統開銷小,系統不需要建立新的程序或者執行緒,也不需要維護這些程序和執行緒的執行,降底了系統的維護工作量,節省了系統資源,

python提供了selector模組來實現io多路復用。同時,不同的作業系統上,這中間人的可選則的型別是不同的,目前常見的有,epoll, kqueue, devpoll, poll,select等;kqueue(bsd,mac支援),devpoll(solaris支援)和epoll的實現基本相同,epoll在linux2.5+核心中實現,windows系統只實現了select。

select和poll使用輪詢的方式去檢測監視的所有io是否有資料返回,需要不斷的遍歷每乙個io物件,這是一種費時的操作,效率較低。poll優於select的一點是select限制了最大監視io數為1024,這對於需要大量網路io連線的伺服器來顯然是不夠的;而poll對於這個個數沒有限制。但是這同樣面臨問題,在使用輪詢的方式監視這些io時,io數越大,意味著每一次輪詢消耗的時間越多。效率也就越低,這是輪詢無法解決的問題。

e就是為了解決這樣的問題誕生的,首先他沒有最大的監視的io數的限制,並且沒有使用輪詢的方式去檢測這些io,而是採用了事件通知機制和**來獲取這些有訊息返回的io物件,只有「活躍」的io才會主動的去呼叫callback程式設計客棧函式。這個io將會直接被處理而不需要輪詢。

import selectors

import socket

# 建立乙個socketio物件,監聽後將可以接受請求訊息了

sock = socket.socket()

sock.bind(("127.0.0.1", 80))

sock.listen()

slt = selectors.defaultselector() # 使用系統預設selector,windows為select,linux為epoll

# 將這個socketio物件加入到,select中監視

slt.register(fileobj=sock, events=selectors.event_read, data=none)

# 迴圈處理訊息

while true:

# select方法:輪詢這個selector,當有至少乙個io物件有訊息返回時候,將會返回這個有訊息的io物件

ready_events = slt.select(timeout=none)

print(ready_events) # 準備好的io物件們

break

ready_events為乙個列表(代表註冊到這個select中的所有的有資料可接收io物件),列表中的每乙個元組為:

selectorkey物件:

mask值

例如:[(selectorkey(fileobj=bbcabyxqt;, fd=456, events=1, data=none),

1)]處理這個請求,只需要使用該socket對應方法即可,該socket用於接收請求的連線,使用accept方法就可以處理這個請求。

當程式設計客棧接受請求之後,又將會產生新的客戶端,我們將其放入selector中一併監視,當有訊息來時,如果是連線請求,handle_request()函式處理,如果是客戶端的訊息,handle_client_msg()函式處理。

對於select中有兩類socket,所以我們需要判斷被啟用後返回的socket是哪一種,再呼叫不同的函式做不同的請求。如果這個select中的socket種類有很多,將無法如此判斷。解決辦法就是將處理函式繫結到對應的selectkey物件中,可以使用data引數。

def handle_request(sock:socket.socket, mask): # 處理新連線

conn, addr = sock.accept()

conn.setblocking(false) # 設定非阻塞

slt.register(conn, selector.event_read, data=handle_client_msg)

def handle_client_msg(sock:socket.socket, mask) # 處理訊息

data = sock.recv()

print(data.decode())

sock = socket.socket()

sock.bind(("127.0.0.1", 80))

sock.listen()

slt = selectors.defaultselector()

slt.register(fileobj=sock, events=selectors.event_read, data=handle_request)

while true:

ready_events = slt.select(timeout=none)

for event, mask in ready_events:

event.data(event.fileobj, mask)

# 不同的socket有不同data函式,使用自己繫結的data函式呼叫,再將自己的socket作為引數。就可以處理不同型別的socket。

上面使用data很好的解決了上面問題,但是需要注意,繫結到data屬性上函式(或者說可呼叫物件)最終會使用event.data(event.fileobj)的方式呼叫,這些函式接受的引數應該相同。

Linux IO多路復用

一.select 函式 include include include int select int n,fd set readfds,fd set writefds,fd set exceptfds,struct timeval timeout fd clr int fd,fd set set f...

I O多路復用

一 五種i o模型 1 阻塞i o模型 最流行的i o模型是阻塞i o模型,預設情形下,所有套介面都是阻塞的。我們以資料報套介面為例來講解此模型 我們使用udp而不是tcp作為例子的原因在於就udp而言,資料準備好讀取的概念比較簡單 要麼整個資料報已經收到,要麼還沒有。然而對於tcp來說,諸如套介面...

Linux C Socket多路復用

1.迴圈伺服器 udp伺服器 udp迴圈伺服器的實現非常簡單 udp伺服器每次從套接字上讀取乙個客戶端的請求,處理,然後將結果返回給客戶機.可以用下面的演算法來實現.socket bind while 1 因為udp是非面向連線的,沒有乙個客戶端可以老是佔住服務端.只要處理過程不是死迴圈,伺服器對於...