龙卷风的IOLoop.call_later是令人费解的行为
问题描述:
从一个解释器会话:龙卷风的IOLoop.call_later是令人费解的行为
>>>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没有按”吨似乎运行与加ll_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()阻止?我不认为这可能是问题所在。我现在必须重新考虑我整个程序的架构。
答
未捕获的异常(在本例中为KeyboardInterrupt
)将使IOLoop
处于未定义状态。发生这种异常后无法重新启动IOLoop
(因为它可能在任何时候出现,并且使IOLoop
的内部不一致)。一般而言,假定该过程将在KeyboardInterrupt
之后简单地退出。可以创建一个新的IOLoop
并重新开始,但是您必须小心重新创建所有依赖它的对象。
不幸的是,这意味着在交互式解释器中使用Tornado实际上很困难。我通常用于开发Tornado应用程序的工作流程是使用python -m tornado.autoreload
运行脚本,并让脚本在我编辑它时从头开始重新运行。
你使用什么版本的python和龙卷风? ioloop是否在另一个线程中运行? call_later不是线程安全的。 – kwarunek
Python 3.6,最新版本的Tornado。 这里不确定你对线程安全的意义。我没有对线程做任何特殊的处理。 –
从Tornado的文档add_timeout(也适用于call_later) - http://www.tornadoweb.org/en/stable/ioloop.html#tornado.ioloop.IOLoop.add_timeout:请注意,从其他线程调用add_timeout并不安全。相反,您必须使用add_callback将控制权转移给IOLoop的线程,然后从那里调用add_timeout。 – kwarunek