Tornado的IOLoop.call_later表现得莫名其妙

时间:2017-06-13 15:52:16

标签: python tornado

来自口译员会议:

>>>io_loop.call_later(comments_page_delay, functools.partial(http_client.fetch, "google.com", lambda x: print('kek')))
<tornado.ioloop._Timeout object at 0x7fe9a2427b08>
>>> io_loop.start()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.6/site-packages/tornado/ioloop.py", line 755, in start
    raise RuntimeError("IOLoop is already running")
RuntimeError: IOLoop is already running
>>> io_loop.call_later(comments_page_delay, functools.partial(http_client.fetch, "google.com", lambda x: print('kek')))
<tornado.ioloop._Timeout object at 0x7fe9a0267808>
>>> io_loop.stop()
>>> io_loop.start()
>>> io_loop.start()
kek
kek
kek

下面:

io_loop = tornado.ioloop.IOLoop.current()
comments_page_delay = 0.1

编辑:

AsyncHTTPClient.configure("tornado.curl_httpclient.CurlAsyncHTTPClient")
http_client = AsyncHTTPClient()
http_client.max_clients = max_clients
http_client.request_timeout = request_timeout

问题:

ioloop似乎没有运行call_later添加的呼叫。它正在运行,正如我尝试执行io_loop.start()时的错误所证明的那样。为了让它实际执行,我必须首先停止循环,然后启动它两次 ...非常混乱。

我承认自从我使用Tornado以来已经有一段时间了,但这基本上等同于我所知道的其他代码。

编辑:代码在第一次运行时正常运行,但在连续运行时无效。此时需要运行io_loop.start()两次返回

这里是完整的代码(略有删失):

"""...docstring..."""
import functools

import tornado
from tornado.httpclient import AsyncHTTPClient
from lxml import html as lh

from config import comments_page_delay, max_clients, request_timeout
from debug import log

AsyncHTTPClient.configure("tornado.curl_httpclient.CurlAsyncHTTPClient")
http_client = AsyncHTTPClient()
http_client.max_clients = max_clients
http_client.request_timeout = request_timeout

io_loop = tornado.ioloop.IOLoop.current()

def x(y, proxy):
    """...docstring..."""
    def handle_response(response):
        if response.error:
            log('...message...'
                .format(uid, response.error), 1)
        else:
            print('Worked')
            data = response.body

    comments_url = "...valid url..."

    io_loop.call_later(comments_page_delay, functools.partial(http_client.fetch, comments_url, handle_response,
                                                              proxy_host=proxy['host'], proxy_port=proxy['port']))

x(1, {'host': None, 'port': None})

io_loop.start()
print('ok')
io_loop.stop()

我在Emacs python解释器会话中运行代码,如果这在某种程度上是相关的。我会在一秒钟内尝试正常的python会话。

EDIT2 :如果我在普通的python解释器中运行该代码会发生什么:

$ python -i fetch.py
Worked


Traceback (most recent call last):
  File "fetch.py", line 34, in <module>
    io_loop.start()
  File "/usr/lib/python3.6/site-packages/tornado/ioloop.py", line 863, in start
    event_pairs = self._impl.poll(poll_timeout)
KeyboardInterrupt
>>> >>> >>> get_user_profile_link(1, {'host': None, 'port': None})
>>> 
>>> 
>>> io_loop.start()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.6/site-packages/tornado/ioloop.py", line 755, in start
    raise RuntimeError("IOLoop is already running")
RuntimeError: IOLoop is already running
>>> io_loop.stop()
>>> io_loop.start()
>>> io_loop.start()
Worked

看来io_loop.start()阻塞了吗?我没想到,这可能是问题所在。我现在必须重新思考整个程序的架构。

1 个答案:

答案 0 :(得分:0)

未捕获的异常(在这种情况下为KeyboardInterrupt)使IOLoop处于未定义状态。在发生此类异常后,无法重新启动IOLoop(因为它可能在任何时候出现并使IOLoop的内部结构不一致)。一般来说,它假设该过程将在KeyboardInterrupt之后退出。可以创建新的IOLoop并重新开始使用它,但是您必须小心重新创建依赖于它的所有对象。

不幸的是,这意味着将Tornado与交互式解释器一起使用实际上很困难。我开发Tornado应用程序的常用工作流程是使用python -m tornado.autoreload运行脚本,并在编辑脚本时让脚本从头开始重新运行。