Gevent工作原理(轉)


作者:大U哥
鏈接:https://www.zhihu.com/question/20703476/answer/15911452
來源:知乎
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

gevent 比起其他框架(比如tornado,twisted)的一個巨大優勢就是:用同步的方法(自然沒有回調函數)寫異步應用,因為同步的方式更接近開發人員的編程思維。
gevent可以用一句話向pythoner闡述:使用多路IO復用對文件描述符的事件監聽,從而撬動協程的“透明”切換。這句話說起來容易,但是闡述起來就復雜些:
  1. 底層(或者說主協程)自然有一個多路IO復用循環(linux上是epoll,unix是kqueue,以下統一用epoll代替描述)
  2. 當處理一個socket鏈接時,就創建一個協程greenlet去處理。
  3. 當socket遇到阻塞的時候,比如等待數據的返回或者發送,此時gevent做了很關鍵的兩步:
    1. 為這個socket的fd在epoll上添加可讀或者可寫事件回調,而這個回調函數便是 gevent.getcurrent().switch
    2. 通過 get_hub().switch() 切換到主協程。切換回主協程,去干其他事情了。但是當該socket可讀或者可寫,epoll自然會調用上述添加的回調函數,從而切換回socket的處理協程,從上次懸掛點接着往下執行。
之所以做到透明,是因為python socket上打了patch。所謂打patch,就是自己實現了一個socket模塊替換了python的標准socket模塊。
def patch_socket():
from gevent import socket
_socket = __import__('socket')
_socket.socket = socket.socket
...
gevent實現的socket模塊,比起python的標准socket模塊,做了以下修改:
  1. 將所有的socket設置成非阻塞。
  2. 修改關鍵函數,比如send,recv,發生阻塞(捕獲到異常 EWOULDBLOCK)時,在socket的fd添加回調函數,並跳回到主協程。

綜上所述,gevent不是沒有事件監聽回調,而是通過給python socket打patch,使其透明化,最終達到讓編程人員用同步的思維去開發。
ps,給python socket打patch,固然好,但是有個小缺點,就是: python c擴展模塊中的socket並不受gevent的管制和調度,因此用在gevent中的網絡庫,都盡量使用純python庫


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM