最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

python Tornado事件循環(huán)示例源碼解析

 更新時間:2023年09月08日 09:32:13   作者:BruceChen7  
這篇文章主要為大家介紹了python Tornado事件循環(huán)示例源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

hello world

#!/usr/bin/env python
import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web
from tornado.options import define, options
define("port", default=8888, help="run on the given port", type=int)
class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, world")
def main():
    tornado.options.parse_command_line()
    application = tornado.web.Application([
        (r"/", MainHandler),
    ])
    http_server = tornado.httpserver.HTTPServer(application)
    http_server.listen(options.port)
    tornado.ioloop.IOLoop.instance().start()
if __name__ == "__main__":
    main()

tornado提供了高效的異步機(jī)制,我們先不管Application實(shí)例化過程,以及http_server創(chuàng)建socket、bind、listen的過程,直接調(diào)IOLoop.instance().start進(jìn)行源碼分析。

IOLoop.instance()

    @classmethod
    def instance(cls):
        """Returns a global IOLoop instance.
        Most single-threaded applications have a single, global IOLoop.
        Use this method instead of passing around IOLoop instances
        throughout your code.
        A common pattern for classes that depend on IOLoops is to use
        a default argument to enable programs with multiple IOLoops
        but not require the argument for simpler applications:
            class MyClass(object):
                def __init__(self, io_loop=None):
                    self.io_loop = io_loop or IOLoop.instance()
        """
        if not hasattr(cls, "_instance"):
            cls._instance = cls()
        return cls._instance

顯然是一個單例模式,注意tornado中的注釋,大多數(shù)單線程只能有一個ioloop。

start()

這個函數(shù)將開始事件循環(huán)。

def start():
     """
     Starts the I/O loop.
     The loop will run until one of the I/O handlers calls stop(), which
      will make the loop stop after the current event iteration completes.
      """
        # 判斷是否設(shè)置了,如果是,將直接退出。
        if self._stopped:
            self._stopped = False
            return
        self._running = True
        while True:
            # Never use an infinite timeout here - it can stall epoll
            # 設(shè)置輪詢時間
            poll_timeout = 0.2
            # Prevent IO event starvation by delaying new callbacks
            # to the next iteration of the event loop.
            callbacks = self._callbacks
            self._callbacks = []
            # 及時調(diào)用回調(diào)函數(shù)
            for callback in callbacks:
                self._run_callback(callback)
            if self._callbacks:
                poll_timeout = 0.0
            # 如果設(shè)置了超時時間
            if self._timeouts:
                # 獲取當(dāng)前時間
                now = time.time()
                while self._timeouts and self._timeouts[0].deadline <= now:
                    timeout = self._timeouts.pop(0)
                    self._run_callback(timeout.callback)
                if self._timeouts:
                    milliseconds = self._timeouts[0].deadline - now
                    poll_timeout = min(milliseconds, poll_timeout)
            # 再一次檢查事件循環(huán)是否在運(yùn)行
            if not self._running:
                break
            # 目前不清楚作用
            if self._blocking_signal_threshold is not None:
                # clear alarm so it doesn't fire while poll is waiting for
                # events.
                signal.setitimer(signal.ITIMER_REAL, 0, 0)

            try:
                # 開始等待事件發(fā)生
                # _impl初始化和poll源代碼見下面
                event_pairs = self._impl.poll(poll_timeout)
            except Exception, e:
                # Depending on python version and IOLoop implementation,
                # different exception types may be thrown and there are
                # two ways EINTR might be signaled:
                # * e.errno == errno.EINTR
                # * e.args is like (errno.EINTR, 'Interrupted system call')
                if (getattr(e, 'errno', None) == errno.EINTR or
                    (isinstance(getattr(e, 'args', None), tuple) and
                     len(e.args) == 2 and e.args[0] == errno.EINTR)):
                    continue
                else:
                    raise
            if self._blocking_signal_threshold is not None:
                signal.setitimer(signal.ITIMER_REAL,
                                 self._blocking_signal_threshold, 0)
            # Pop one fd at a time from the set of pending fds and run
            # its handler. Since that handler may perform actions on
            # other file descriptors, there may be reentrant calls to
            # this IOLoop that update self._events
            self._events.update(event_pairs)
            while self._events:
                fd, events = self._events.popitem()
                try:
                    # 見下面的分析
                    self._handlers[fd](fd, events)
                except (KeyboardInterrupt, SystemExit):
                    raise
                except (OSError, IOError), e:
                    if e.args[0] == errno.EPIPE:
                        # Happens when the client closes the connection
                        pass
                    else:
                        logging.error("Exception in I/O handler for fd %d",
                                      fd, exc_info=True)
                except:
                    logging.error("Exception in I/O handler for fd %d",
                                  fd, exc_info=True)
        # reset the stopped flag so another start/stop pair can be issued
        self._stopped = False
        if self._blocking_signal_threshold is not None:
            signal.setitimer(signal.ITIMER_REAL, 0, 0)

我們看看輸入localhost:8888,event_pairs的值:

可以看出,event_pairs是一個元組列表,其中第一個成員4為accept套接字值,1表示為事件類型。我們看看事件類型為:

 _EPOLLIN = 0x001
 _EPOLLPRI = 0x002
 _EPOLLOUT = 0x004  
 _EPOLLERR = 0x008
 _EPOLLHUP = 0x010
 _EPOLLRDHUP = 0x2000
 _EPOLLONESHOT = (1 << 30)
 _EPOLLET = (1 << 31)
 NONE = 0
 READ = _EPOLLIN
 WRITE = _EPOLLOUT
 ERROR = _EPOLLERR | _EPOLLHUP | _EPOLLRDHUP

可見上述,是文件描述符4,可讀事件發(fā)生。

self._impl

我們跟蹤self._impl初始化過程,可以看到事件循環(huán)核心epoll是如何被使用的。在IOLoop實(shí)例化開始:

class IOLoop(object):
    def __init__(self, impl = None):
        self._impl = impl or _poll

# Choose a poll implementation. Use epoll if it is available, fall back to
# select() for non-Linux platforms
# hasattr(object, attrname)表示某個對象中是否包含屬性
if hasattr(select, "epoll"):
    # Python 2.6+ on Linux
    # 在linux上使用的是select.epoll
    _poll = select.epoll
elif hasattr(select, "kqueue"):
    # Python 2.6+ on BSD or Mac
    _poll = _KQueue
else:
    try:
        # Linux systems with our C module installed
        import epoll
        _poll = _EPoll
    except:
        # All other systems
        import sys
        if "linux" in sys.platform:
            logging.warning("epoll module not found; using select()")
        _poll = _Select

從上面的代碼中,可以看到,_poll是對于多個平臺下epoll、_kQueue的抽象??匆幌聅elect.epoll下的返回結(jié)果:其返回對象是一個邊沿觸發(fā)的polling對象,當(dāng)然也可以用作水平觸發(fā)。

返回的select.epoll對象的方法:

  • epoll.close() 關(guān)閉epoll fd文件描述符
  • epoll.fileno() 返回epoll fd文件描述符只
  • epoll.register(fd, eventmask) 注冊fd某個事件
  • epoll.poll([timeout = -1, maxevents = -1]) wait for events. timeout in seconds

self._handlers[fd](fd, events)

顯然,self._handlers[fd]是返回一個回調(diào)函數(shù),用來處理fd上的事件events,這里測試的fd為4,事件EPOLLIN。我們來跟蹤一下self._handlers變化過程。看看在IOLoop初始化的過程。

def __init__(self):
    self._handles = {}
    ....
    if os.name != 'nt':
        r, w = os.pipe()
        self._set_nonblocking(r)
        self._set_nonblocking(w)
        .....
        self._waker_reader = os.fdopen(r, "rb", 0)
        self._waker_writer = os.fdopen(w, "wb", 0)    
    # 顯然這是對讀管道文件描述符事件處理函數(shù)
    self.add_handler(r, self._read_waker, self.READ)

add_handler(self, fd, handler, events)

def add_handler(self, fd, handler, events):
    self._handlers[fd] = stack_context.wrap(handler)
    self._impl.register(fd, events| self.ERROR)

可見add_handler干了兩件事情:

  • 回調(diào)函數(shù)設(shè)置,當(dāng)然不僅僅是簡單的將handler賦值,而是使用了stack_context.wrap包裹了該函數(shù),具體實(shí)現(xiàn),見下面。
  • epoll對象添加該事件,就是在代碼的第二行。所以self._handlers[fd](fd, args)實(shí)際上就是設(shè)置的回調(diào)函數(shù)。那么用stack_context.wrap()來包裹究竟是為了什么了?

update_handler(self, fd, events)

 def update_handler(self, fd, events):
        """Changes the events we listen for fd."""
        self._impl.modify(fd, events | self.ERROR)

該函數(shù)用來修改fd感興趣的事件

以上就是python Tornado事件循環(huán)示例源碼解析的詳細(xì)內(nèi)容,更多關(guān)于python Tornado事件循環(huán)的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 使用Python自動化Microsoft Excel和Word的操作方法

    使用Python自動化Microsoft Excel和Word的操作方法

    這篇文章主要介紹了使用Python自動化Microsoft Excel和Word,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-04-04
  • python的簡單web框架flask快速實(shí)現(xiàn)詳解

    python的簡單web框架flask快速實(shí)現(xiàn)詳解

    這篇文章主要為大家介紹了python的簡單web框架flask快速實(shí)現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-02-02
  • TensorFlow saver指定變量的存取

    TensorFlow saver指定變量的存取

    這篇文章主要為大家詳細(xì)介紹了TensorFlow saver指定變量的存取,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-03-03
  • Flask框架Jinjia模板常用語法總結(jié)

    Flask框架Jinjia模板常用語法總結(jié)

    這篇文章主要介紹了Flask框架Jinjia模板常用語法,結(jié)合實(shí)例形式總結(jié)分析了Jinjia模板的變量、賦值、流程控制、函數(shù)、塊、宏等基本使用方法,需要的朋友可以參考下
    2018-07-07
  • Python?Pywinauto輕松實(shí)現(xiàn)Windows桌面自動化詳解

    Python?Pywinauto輕松實(shí)現(xiàn)Windows桌面自動化詳解

    pywinauto這個Python庫可以讓你像魔法師一樣操控Windows?GUI,輕松模擬鼠標(biāo)鍵盤操作,自動化Notepad,Excel甚至企業(yè)級軟件,下面小編就來和大家詳細(xì)介紹一下它的使用吧
    2025-05-05
  • Python Numpy:找到list中的np.nan值方法

    Python Numpy:找到list中的np.nan值方法

    今天小編就為大家分享一篇Python Numpy:找到list中的np.nan值方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-10-10
  • python實(shí)現(xiàn)小程序推送頁面收錄腳本

    python實(shí)現(xiàn)小程序推送頁面收錄腳本

    這篇文章主要介紹了python實(shí)現(xiàn)小程序推送頁面收錄腳本,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-04-04
  • python如何獲取當(dāng)前文件夾下所有文件名詳解

    python如何獲取當(dāng)前文件夾下所有文件名詳解

    這篇文章主要給大家介紹了關(guān)于python如何獲取當(dāng)前文件夾下所有文件名的相關(guān)資料,文中給出了詳細(xì)的示例代碼,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起看看吧
    2019-01-01
  • python中sympy庫求常微分方程的用法

    python中sympy庫求常微分方程的用法

    這篇文章主要介紹了python中sympy庫求常微分方程的用法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-04-04
  • python如何通過Json路徑返回Json響應(yīng)對應(yīng)的值

    python如何通過Json路徑返回Json響應(yīng)對應(yīng)的值

    這篇文章主要介紹了python如何通過Json路徑返回Json響應(yīng)對應(yīng)的值問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-06-06

最新評論

明光市| 偏关县| 卢龙县| 十堰市| 桦南县| 和静县| 香港| 丹棱县| 合阳县| 互助| 喀什市| 涞源县| 宝坻区| 巨鹿县| 航空| 抚宁县| 永寿县| 信阳市| 柘城县| 威海市| 巴彦淖尔市| 郯城县| 靖安县| 东乡县| 太原市| 左贡县| 通许县| 康平县| 色达县| 宿迁市| 民和| 祁东县| 屯留县| 鹤山市| 垫江县| 繁昌县| 康乐县| 尼勒克县| 万宁市| 莆田市| 城固县|