国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Python > 正文

深入理解python中的select模塊

2019-11-25 16:14:03
字體:
來源:轉載
供稿:網友

簡介

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

select方法

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

當我們調用select()時:

  1、上下文切換轉換為內核態

  2、將fd從用戶空間復制到內核空間

  3、內核遍歷所有fd,查看其對應事件是否發生

  4、如果沒發生,將進程阻塞,當設備驅動產生中斷或者timeout時間后,將進程喚醒,再次進行遍歷

  5、返回遍歷后的fd

  6、將fd從內核空間復制到用戶空間

fd:file descriptor 文件描述符

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

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

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

返回值:三個列表

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

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

    2、當參數2 序列中含有fd時,則將該序列中所有的fd添加到 fd_w_list中

    3、當參數3 序列中的fd發生錯誤時,則將該發生錯誤的fd添加到 fd_e_list中

    4、當超時時間為空,則select會一直阻塞,直到監聽的句柄發生變化

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

實例:利用select實現一個可并發的服務端

import socketimport selects = socket.socket()s.bind(('127.0.0.1',8888))s.listen(5)r_list = [s,]num = 0while 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 socketflag = 1s = 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()

在服務端我們可以看到,我們需要不停的調用select, 這就意味著:

  1  當文件描述符過多時,文件描述符在用戶空間與內核空間進行copy會很費時

  2  當文件描述符過多時,內核對文件描述符的遍歷也很浪費時間

  3  select最大僅僅支持1024個文件描述符

poll與select相差不大,本文不作介紹

epoll方法:

epoll很好的改進了select:

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

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

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

select.epoll(sizehint=-1, flags=0) 創建epoll對象epoll.close()Close the control file descriptor of the epoll object.關閉epoll對象的文件描述符epoll.closedTrue if the epoll object is closed.檢測epoll對象是否關閉epoll.fileno()Return the file descriptor number of the control fd.返回epoll對象的文件描述符epoll.fromfd(fd)Create an epoll object from a given file descriptor.根據指定的fd創建epoll對象epoll.register(fd[, eventmask])Register a fd descriptor with the epoll object.向epoll對象中注冊fd和對應的事件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事件發生,會返回一個dict,格式為:{(fd1,event1),(fd2,event2),……(fdn,eventn)}

事件:

EPOLLIN Available for read 可讀 狀態符為1EPOLLOUT Available for write 可寫 狀態符為4EPOLLPRI Urgent data for readEPOLLERR Error condition happened on the assoc. fd 發生錯誤 狀態符為8EPOLLHUP Hang up happened on the assoc. fd 掛起狀態EPOLLET Set Edge Trigger behavior, the default is Level Trigger behavior 默認為水平觸發,設置該事件后則邊緣觸發EPOLLONESHOT Set one-shot behavior. After one event is pulled out, the fd is internally disabledEPOLLRDNORM Equivalent to EPOLLINEPOLLRDBAND Priority data band can be read.EPOLLWRNORM Equivalent to EPOLLOUTEPOLLWRBAND Priority data may be written.EPOLLMSG Ignored.

水平觸發和邊緣觸發:

Level_triggered(水平觸發,有時也稱條件觸發):當被監控的文件描述符上有可讀寫事件發生時,epoll.poll()會通知處理程序去讀寫。如果這次沒有把數據一次性全部讀寫完(如讀寫緩沖區太小),那么下次調用 epoll.poll()時,它還會通知你在上沒讀寫完的文件描述符上繼續讀寫,當然如果你一直不去讀寫,它會一直通知你!!!如果系統中有大量你不需要讀寫的就緒文件描述符,而它們每次都會返回,這樣會大大降低處理程序檢索自己關心的就緒文件描述符的效率!!! 優點很明顯:穩定可靠

Edge_triggered(邊緣觸發,有時也稱狀態觸發):當被監控的文件描述符上有可讀寫事件發生時,epoll.poll()會通知處理程序去讀寫。如果這次沒有把數據全部讀寫完(如讀寫緩沖區太小),那么下次調用epoll.poll()時,它不會通知你,也就是它只會通知你一次,直到該文件描述符上出現第二次可讀寫事件才會通知你!!!這種模式比水平觸發效率高,系統不會充斥大量你不關心的就緒文件描述符!!!缺點:某些條件下不可靠

epoll實例:

import socketimport selects = 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 socketflag = 1s = 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()

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對武林網的支持。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 旺苍县| 永年县| 合山市| 砀山县| 永康市| 洞口县| 九龙县| 西吉县| 忻州市| 鹤岗市| 卓尼县| 大英县| 哈尔滨市| 崇文区| 如东县| 乐都县| 南雄市| 青海省| 岳西县| 福州市| 开封县| 广德县| 永登县| 武邑县| 白城市| 黑龙江省| 锡林浩特市| 建湖县| 平凉市| 喀什市| 兴山县| 金山区| 黄浦区| 昌平区| 渝北区| 长春市| 通榆县| 德钦县| 新绛县| 罗山县| 巩义市|