溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

python中的select模塊有什么用

發(fā)布時間:2020-09-24 15:19:31 來源:億速云 閱讀:277 作者:Leah 欄目:編程語言

這篇文章運用簡單易懂的例子給大家介紹python中的select模塊有什么用,內(nèi)容非常詳細(xì),感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。

簡介

Python中的select模塊專注于I/O多路復(fù)用,提供了select  poll  epoll三個方法(其中后兩個在Linux中可用,windows僅支持select),另外也提供了kqueue方法(freeBSD系統(tǒng))

select方法

進(jìn)程指定內(nèi)核監(jiān)聽哪些文件描述符(最多監(jiān)聽1024個fd)的哪些事件,當(dāng)沒有文件描述符事件發(fā)生時,進(jìn)程被阻塞;當(dāng)一個或者多個文件描述符事件發(fā)生時,進(jìn)程被喚醒。

當(dāng)我們調(diào)用select()時:

1、上下文切換轉(zhuǎn)換為內(nèi)核態(tài)

2、將fd從用戶空間復(fù)制到內(nèi)核空間

3、內(nèi)核遍歷所有fd,查看其對應(yīng)事件是否發(fā)生

4、如果沒發(fā)生,將進(jìn)程阻塞,當(dāng)設(shè)備驅(qū)動產(chǎn)生中斷或者timeout時間后,將進(jìn)程喚醒,再次進(jìn)行遍歷

5、返回遍歷后的fd

6、將fd從內(nèi)核空間復(fù)制到用戶空間

fd:file descriptor 文件描述符

fd_r_list, fd_w_list, fd_e_list = select.select(rlist, wlist, xlist, [timeout])

參數(shù): 可接受四個參數(shù)(前三個必須)

rlist: wait until ready for reading
wlist: wait until ready for writing
xlist: wait for an “exceptional condition”
timeout: 超時時間

返回值:三個列表

select方法用來監(jiān)視文件描述符(當(dāng)文件描述符條件不滿足時,select會阻塞),當(dāng)某個文件描述符狀態(tài)改變后,會返回三個列表

1、當(dāng)參數(shù)1 序列中的fd滿足“可讀”條件時,則獲取發(fā)生變化的fd并添加到fd_r_list中

2、當(dāng)參數(shù)2 序列中含有fd時,則將該序列中所有的fd添加到 fd_w_list中

3、當(dāng)參數(shù)3 序列中的fd發(fā)生錯誤時,則將該發(fā)生錯誤的fd添加到 fd_e_list中

4、當(dāng)超時時間為空,則select會一直阻塞,直到監(jiān)聽的句柄發(fā)生變化

當(dāng)超時時間 = n(正整數(shù))時,那么如果監(jiān)聽的句柄均無任何變化,則select會阻塞n秒,之后返回三個空列表,如果監(jiān)聽的句柄有變化,則直接執(zhí)行。

實例

利用select實現(xiàn)一個可并發(fā)的服務(wù)

import socket
import select
  
s = socket.socket()
s.bind(('127.0.0.1',8888))
s.listen(5)
r_list = [s,]
num = 0
while True:
 rl, wl, error = select.select(r_list,[],[],10)
 num+=1
 print('counts is %s'%num)
 print("rl's length is %s"%len(rl))
 for fd in rl:
  if fd == s:
   conn, addr = fd.accept()
   r_list.append(conn)
   msg = conn.recv(200)
   conn.sendall(('first----%s'%conn.fileno()).encode())
  else:
   try:
    msg = fd.recv(200)
    fd.sendall('second'.encode())
   except ConnectionAbortedError:
    r_list.remove(fd)
  
s.close()
import socket
  
flag = 1
s = socket.socket()
s.connect(('127.0.0.1',8888))
while flag:
 input_msg = input('input>>>')
 if input_msg == '0':
  break
 s.sendall(input_msg.encode())
 msg = s.recv(1024)
 print(msg.decode())
  
s.close()

epoll方法:

epoll很好的改進(jìn)了select:

1、epoll的解決方案在epoll_ctl函數(shù)中。每次注冊新的事件到epoll句柄中時,會把所有的fd拷貝進(jìn)內(nèi)核,而不是在epoll_wait的時候重復(fù)拷貝。epoll保證了每個fd在整個過程中只會拷貝一次。

2、epoll會在epoll_ctl時把指定的fd遍歷一遍(這一遍必不可少)并為每個fd指定一個回調(diào)函數(shù),當(dāng)設(shè)備就緒,喚醒等待隊列上的等待者時,就會調(diào)用這個回調(diào)函數(shù),而這個回調(diào)函數(shù)會把就緒的fd加入一個就緒鏈表。epoll_wait的工作實際上就是在這個就緒鏈表中查看有沒有就緒的fd

3、epoll對文件描述符沒有額外限制

select.epoll(sizehint=-1, flags=0) 創(chuàng)建epoll對象
epoll.close()
Close the control file descriptor of the epoll object.關(guān)閉epoll對象的文件描述符
epoll.closed
True if the epoll object is closed.檢測epoll對象是否關(guān)閉
epoll.fileno()
Return the file descriptor number of the control fd.返回epoll對象的文件描述符
epoll.fromfd(fd)
Create an epoll object from a given file descriptor.根據(jù)指定的fd創(chuàng)建epoll對象
epoll.register(fd[, eventmask])
Register a fd descriptor with the epoll object.向epoll對象中注冊fd和對應(yīng)的事件
epoll.modify(fd, eventmask)
Modify a registered file descriptor.修改fd的事件
epoll.unregister(fd)
Remove a registered file descriptor from the epoll object.取消注冊
epoll.poll(timeout=-1, maxevents=-1)
Wait for events. timeout in seconds (float)阻塞,直到注冊的fd事件發(fā)生,會返回一個dict,格式為:{(fd1,event1),
(fd2,event2),……(fdn,eventn)}

epoll實例:

import socket
import select
  
s = socket.socket()
s.bind(('127.0.0.1',8888))
s.listen(5)
epoll_obj = select.epoll()
epoll_obj.register(s,select.EPOLLIN)
connections = {}
while True:
 events = epoll_obj.poll()
 for fd, event in events:
  print(fd,event)
  if fd == s.fileno():
   conn, addr = s.accept()
   connections[conn.fileno()] = conn
   epoll_obj.register(conn,select.EPOLLIN)
   msg = conn.recv(200)
   conn.sendall('ok'.encode())
  else:
   try:
    fd_obj = connections[fd]
    msg = fd_obj.recv(200)
    fd_obj.sendall('ok'.encode())
   except BrokenPipeError:
    epoll_obj.unregister(fd)
    connections[fd].close()
    del connections[fd]
  
s.close()
epoll_obj.close()
import socket
  
flag = 1
s = socket.socket()
s.connect(('127.0.0.1',8888))
while flag:
 input_msg = input('input>>>')
 if input_msg == '0':
  break
 s.sendall(input_msg.encode())
 msg = s.recv(1024)
 print(msg.decode())
  
s.close()

關(guān)于python中的select模塊有什么用就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI