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

python?tornado協(xié)程調(diào)度原理示例解析

 更新時(shí)間:2023年09月08日 09:34:43   作者:菜皮日記  
這篇文章主要為大家介紹了python?tornado協(xié)程調(diào)度原理示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

tornado 的協(xié)程實(shí)現(xiàn)原理

本文討論 tornado 的協(xié)程實(shí)現(xiàn)原理,簡(jiǎn)單做了一份筆記。

首先看一段最常見(jiàn)的 tornado web 代碼:

import tornado
import tornado.web
import tornado.gen
from tornado.gen import coroutine
from tornado.httpclient import AsyncHTTPClient
class GenHandler(tornado.web.RequestHandler):
    @coroutine
    def get(self):
        url = 'http://www.baidu.com'
        http_client = AsyncHTTPClient()
        response = yield http_client.fetch(url)
        yield tornado.gen.sleep(5)
        self.write(response.body)
class MainHanler(tornado.web.RequestHandler):
    def get(self):
        self.write('root')
if __name__ == "__main__":
    application = tornado.web.Application([
        (r"/", MainHanler),
        (r"/gen_async/", GenHandler),
    ], autoreload=True)
    application.listen(8888)
    tornado.ioloop.IOLoop.current().start()

其中最后一行代碼 tornado.ioloop.IOLoop.current().start() 啟動(dòng)服務(wù)。

帶著幾個(gè)問(wèn)題往下看:

  • 知道 yield 可以暫存執(zhí)行狀態(tài),等「合適的時(shí)機(jī)」重新恢復(fù)執(zhí)行,那么保存的狀態(tài)到哪去了?
  • 上一個(gè)問(wèn)題中「合適的時(shí)機(jī)」是到底是什么時(shí)候?
  • 繼續(xù)接上一個(gè)問(wèn)題,具體是怎么恢復(fù)執(zhí)行的?

IOLoop 類(lèi)相當(dāng)于是對(duì)多路復(fù)用的封裝,起到事件循環(huán)的作用,調(diào)度整個(gè)協(xié)程執(zhí)行過(guò)程。

查看 IOLoop 的源碼,可以看到 IOLoop 繼承自 Configurable,PollIOLoop 又繼承自 IOLoop。當(dāng) IOLoop 啟動(dòng)時(shí),會(huì)確定使用哪一種多路復(fù)用方式,epoll、kqueue 還是 select?

# IOLoop 類(lèi)
# IOLoop 中的 configurable_default 方法是重寫(xiě) Configurable 的
# 這里會(huì)確定使用哪種多路復(fù)用方式
@classmethod
def configurable_default(cls):
    if hasattr(select, "epoll"):
        from tornado.platform.epoll import EPollIOLoop
        return EPollIOLoop
    if hasattr(select, "kqueue"):
        # Python 2.6+ on BSD or Mac
        from tornado.platform.kqueue import KQueueIOLoop
      return KQueueIOLoop
    from tornado.platform.select import SelectIOLoop
  return SelectIOLoop
# PollIOLoop類(lèi)
def initialize(self, impl, time_func=None, **kwargs):
    super(PollIOLoop, self).initialize(**kwargs)
    self._impl = impl
    if hasattr(self._impl, 'fileno'):
        set_close_exec(self._impl.fileno())
    self.time_func = time_func or time.time
    self._handlers = {}
    self._events = {}
    self._callbacks = []
    self._callback_lock = threading.Lock()
    self._timeouts = []
    self._cancellations = 0
    self._running = False
    self._stopped = False
    self._closing = False
    self._thread_ident = None
    self._blocking_signal_threshold = None
    self._timeout_counter = itertools.count()

    # Create a pipe that we send bogus data to when we want to wake
    # the I/O loop when it is idle
    self._waker = Waker()
    self.add_handler(self._waker.fileno(),
                     lambda fd, events: self._waker.consume(),
                     self.READ)

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

def update_handler(self, fd, events):
    fd, obj = self.split_fd(fd)
    self._impl.modify(fd, events | self.ERROR)

def remove_handler(self, fd):
    fd, obj = self.split_fd(fd)
    self._handlers.pop(fd, None)
    self._events.pop(fd, None)
    try:
        self._impl.unregister(fd)
    except Exception:
        gen_log.debug("Error deleting fd from IOLoop", exc_info=True)

PollIOLoop 中 initalize 方法中調(diào)用 add_handler 方法,注冊(cè)對(duì)應(yīng)事件的處理函數(shù),如 socket 可讀時(shí),回調(diào)哪個(gè)函數(shù)去處理。

IOLoop 和協(xié)程之間的信使:Future

class Future(object):
    def __init__(self):
        self._result = None
        self._exc_info = None
        self._callbacks = []
        self.running = True
        
    def set_result(self, result):
        ...
        
    def set_exc_info(self, exce_info):
        ...
        
    def result(self):
        ...
    
    def exc_info(self):
        ...
        
    def add_done_callback(self, callback):
        self._callbacks.append(callback)

Future 對(duì)象起到“占位符”的作用,協(xié)程的執(zhí)行結(jié)果會(huì)通過(guò) set_result 方式寫(xiě)入其中,并調(diào)用通過(guò) add_done_callback 設(shè)置的回調(diào)。

恢復(fù)喚醒協(xié)程的 Runner

class Runner(object):
    def __init__(self, gen, result_future, first_yielded):
        self.gen = gen
        self.result_future = result_future
        self.future = _null_future
        self.yield_point = None
        self.pending_callbacks = None
        self.results = None
        self.running = False
        self.finished = False
        self.had_exception = False
        self.io_loop = IOLoop.current()
        self.stack_context_deactivate = None
        # 上面一堆不需要看的初始化
        if self.handle_yield(first_yielded):
            gen = result_future = first_yielded = None
            self.run()
     
    
    def handle_yield(self, yielded):

        self.future = convert_yielded(yielded)

        if self.future is moment:
            self.io_loop.add_callback(self.run)
            return False
        elif not self.future.done():
            def inner(f):
                # Break a reference cycle to speed GC.
                f = None
                self.run()
            self.io_loop.add_future(
                self.future, inner)
            return False
        return True
    
    def run(self):
        if self.running or self.finished:
            return
        try:
            self.running = True
            while True:
                future = self.future
                if not future.done():
                    return
                self.future = None
                try:
                    orig_stack_contexts = stack_context._state.contexts
                    exc_info = None

                    try:
                        value = future.result()
                    except Exception:
                        self.had_exception = True
                        exc_info = sys.exc_info()
                    future = None
  
                    yielded = self.gen.send(value)

                except (StopIteration, Return) as e:
                    self.finished = True
                    self.future = _null_future
                    if self.pending_callbacks and not self.had_exception:
                        raise LeakedCallbackError(
                            "finished without waiting for callbacks %r" %
                            self.pending_callbacks)
                    future_set_result_unless_cancelled(self.result_future,
_value_from_stopiteration(e))
                    self.result_future = None
                    self._deactivate_stack_context()
                    return
                except Exception:
                    # 一些結(jié)束操作
                    return
                if not self.handle_yield(yielded):
                    return
                yielded = None
        finally:
            self.running = False

協(xié)程每生成一個(gè) Future,都會(huì)生成對(duì)應(yīng)的一個(gè) Runner,并將 Future 初始化注入都其中。Runner 的 run 方法中,通過(guò) self.gen.send(Future) 來(lái)啟動(dòng) Future,當(dāng) Future 完成時(shí),將其設(shè)置成 done,并回調(diào)其預(yù)設(shè)的 callback。

第一個(gè)問(wèn)題:協(xié)程的狀態(tài)保存到哪去了

IOLoop 中通過(guò) add_future 調(diào)用實(shí)現(xiàn)類(lèi) PollIOLoop 中的 add_callback 方法,其中通過(guò) functools 生成偏函數(shù),放入 _callbacks 列表,等待被回調(diào)執(zhí)行。

# IOLoop 的add_future
def add_future(self, future, callback):
    """Schedules a callback on the ``IOLoop`` when the given
    `.Future` is finished.

    The callback is invoked with one argument, the
    `.Future`.
    """
    assert is_future(future)
    callback = stack_context.wrap(callback)
    future.add_done_callback(
        lambda future: self.add_callback(callback, future))

# PollIOLoop 的add_callback
def add_callback(self, callback, *args, **kwargs):
        if thread.get_ident() != self._thread_ident:
            with self._callback_lock:
                if self._closing:
                    return
                list_empty = not self._callbacks
                self._callbacks.append(functools.partial(
                    stack_context.wrap(callback), *args, **kwargs))
                if list_empty:
                    self._waker.wake()
        else:
            if self._closing:
                return
            self._callbacks.append(functools.partial(
                stack_context.wrap(callback), *args, **kwargs))

第二個(gè)問(wèn)題:「合適的時(shí)機(jī)」是什么?

IOLoop 實(shí)際上就是對(duì)多路復(fù)用的封裝,當(dāng)?shù)讓?epoll_wait 事件發(fā)生時(shí),即會(huì)通知 IOLoop 主線程。

這一段是 IOLoop 中等待多路復(fù)用的事件,以及處理事件。

try:
    # 等待事件
      event_pairs = self._impl.poll(poll_timeout)
except Exception as e:
      print("wait fail")
      if errno_from_exception(e) == errno.EINTR:
          continue
      else:
          raise
if self._blocking_signal_threshold is not None:
                    signal.setitimer(signal.ITIMER_REAL,
                                     self._blocking_signal_threshold, 0)
# 處理事件
self._events.update(event_pairs)
while self._events:
    fd, events = self._events.popitem()
    try:
        fd_obj, handler_func = self._handlers[fd]
        handler_func(fd_obj, events)
    except (OSError, IOError) as e:
        if errno_from_exception(e) == errno.EPIPE:
            pass
        else:
            self.handle_callback_exception(self._handlers.get(fd))
    except Exception:
        self.handle_callback_exception(self._handlers.get(fd))
fd_obj = handler_func = None

第三個(gè)問(wèn)題:具體是怎么恢復(fù)的。

Runner 通過(guò)不斷 check Future 的狀態(tài),最后調(diào)用 callback 來(lái)返回結(jié)果。

總結(jié)

首先 tornado 對(duì)多路復(fù)用系統(tǒng)調(diào)用做了封裝,來(lái)實(shí)現(xiàn)非阻塞 web 服務(wù)。

其次 tornado 通過(guò) yield+Future+Runner 實(shí)現(xiàn)了生成 Future,Runner 監(jiān)控結(jié)果,回調(diào) callback 來(lái)實(shí)現(xiàn)協(xié)程的執(zhí)行。

參考:

http://m.fzitv.net/python/2976505cr.htm

http://m.fzitv.net/article/132918.htm

tornado的事件循環(huán)機(jī)制

以上就是python tornado協(xié)程調(diào)度原理示例解析的詳細(xì)內(nèi)容,更多關(guān)于python tornado協(xié)程調(diào)度的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Python3中處理和操作純文本文件的詳細(xì)教程

    Python3中處理和操作純文本文件的詳細(xì)教程

    本教程將簡(jiǎn)要描述 Python 能夠處理的一些文件格式,在簡(jiǎn)要介紹這些文件格式之后,你將學(xué)習(xí)如何在 Python 3 中打開(kāi)、讀取和寫(xiě)入文本文件,完成后,你將能夠處理 Python 中的任何純文本文件,需要的朋友可以參考下
    2024-06-06
  • Python實(shí)現(xiàn)訪問(wèn)者模式詳情

    Python實(shí)現(xiàn)訪問(wèn)者模式詳情

    這篇文章主要介紹了Python實(shí)現(xiàn)訪問(wèn)者模式詳情,訪問(wèn)者模式,指作用于一個(gè)對(duì)象結(jié)構(gòu)體上的元素的操作。訪問(wèn)者可以使用戶在不改變?cè)摻Y(jié)構(gòu)體中的類(lèi)的基礎(chǔ)上定義一個(gè)新的操作,下文更多相關(guān)資料,需要的朋友可以參考下
    2022-03-03
  • Python列表list解析操作示例【整數(shù)操作、字符操作、矩陣操作】

    Python列表list解析操作示例【整數(shù)操作、字符操作、矩陣操作】

    這篇文章主要介紹了Python列表list解析操作,結(jié)合實(shí)例形式分析了Python列表針對(duì)整數(shù)、字符及矩陣的解析操作實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2017-07-07
  • Python 數(shù)據(jù)結(jié)構(gòu)之堆棧實(shí)例代碼

    Python 數(shù)據(jù)結(jié)構(gòu)之堆棧實(shí)例代碼

    這篇文章主要介紹了Python 數(shù)據(jù)結(jié)構(gòu)之堆棧實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下
    2017-01-01
  • 90行Python代碼開(kāi)發(fā)個(gè)人云盤(pán)應(yīng)用

    90行Python代碼開(kāi)發(fā)個(gè)人云盤(pán)應(yīng)用

    這篇文章主要介紹了90行Python代碼開(kāi)發(fā)個(gè)人云盤(pán)應(yīng)用,幫助大家更好的理解和學(xué)習(xí)python,感興趣的朋友可以了解下
    2021-04-04
  • 基于Python+ECharts實(shí)現(xiàn)實(shí)時(shí)數(shù)據(jù)大屏

    基于Python+ECharts實(shí)現(xiàn)實(shí)時(shí)數(shù)據(jù)大屏

    文章介紹了如何使用Python爬蟲(chóng)和ECharts構(gòu)建實(shí)時(shí)數(shù)據(jù)大屏,通過(guò)自動(dòng)化數(shù)據(jù)采集和動(dòng)態(tài)數(shù)據(jù)展示,提高決策效率,關(guān)鍵步驟包括爬蟲(chóng)開(kāi)發(fā)、ECharts可視化和系統(tǒng)集成,同時(shí)提供了常見(jiàn)問(wèn)題的解決方案和進(jìn)階方向,需要的朋友可以參考下
    2026-01-01
  • pythotn條件分支與循環(huán)詳解(3)

    pythotn條件分支與循環(huán)詳解(3)

    這篇文章主要介紹了Python條件分支和循環(huán)用法,結(jié)合實(shí)例形式較為詳細(xì)的分析了Python邏輯運(yùn)算操作符,條件分支語(yǔ)句,循環(huán)語(yǔ)句等功能與基本用法,需要的朋友可以參考下
    2021-08-08
  • Flask框架實(shí)現(xiàn)的前端RSA加密與后端Python解密功能詳解

    Flask框架實(shí)現(xiàn)的前端RSA加密與后端Python解密功能詳解

    這篇文章主要介紹了Flask框架實(shí)現(xiàn)的前端RSA加密與后端Python解密功能,結(jié)合實(shí)例形式詳細(xì)分析了flask框架前端使用jsencrypt.js加密與后端Python解密相關(guān)操作技巧,需要的朋友可以參考下
    2019-08-08
  • 詳解Python如何實(shí)現(xiàn)批量為PDF添加水印

    詳解Python如何實(shí)現(xiàn)批量為PDF添加水印

    我們有時(shí)候需要把一些機(jī)密文件發(fā)給多個(gè)客戶,為了避免客戶泄露文件,會(huì)在機(jī)密文件中添加水印。本文將利用Python實(shí)現(xiàn)批量為PDF添加水印,需要的可以參考一下
    2022-05-05
  • 利用Python制作一個(gè)MOOC公開(kāi)課下載器

    利用Python制作一個(gè)MOOC公開(kāi)課下載器

    為了幫助大家更好地在假期內(nèi)卷,本文將利用Python制作一個(gè)中國(guó)大學(xué)MOOC的公開(kāi)課下載器。文中的示例代碼講解詳細(xì),感興趣的小伙伴可以學(xué)習(xí)一下
    2022-03-03

最新評(píng)論

潜山县| 莆田市| 凤山市| 南和县| 旬邑县| 革吉县| 永善县| 许昌市| 五寨县| 修武县| 宁陵县| 开阳县| 淳安县| 长垣县| 巴里| 浦北县| 晋中市| 响水县| 阿勒泰市| 宁武县| 开远市| 来宾市| 土默特右旗| 石狮市| 晋宁县| 衡阳市| 焉耆| 鹰潭市| 肃宁县| 施甸县| 柏乡县| 黎平县| 芷江| 莱芜市| 庆城县| 富裕县| 沐川县| 威远县| 兰坪| 沙河市| 晋中市|