Python 龙卷风';s IOLoop.call\u later的行为令人费解

Python 龙卷风';s IOLoop.call\u later的行为令人费解,python,tornado,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

来自口译员会话:

>>>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
编辑:

问题:

ioloop似乎没有运行稍后添加了call_的调用。它正在运行,当我尝试执行io_loop.start()时出现的错误就是明证。为了让它真正执行,我必须先停止循环,然后启动它两次。。。非常混乱

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

编辑:代码在第一次运行时正常工作,但在连续运行时不能正常工作。在这一点上,需要运行io_loop.start()两次返回

以下是完整的代码(略为删减):

我正在一个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
$python-i fetch.py
工作
回溯(最近一次呼叫最后一次):
文件“fetch.py”,第34行,在
io_loop.start()
文件“/usr/lib/python3.6/site packages/tornado/ioloop.py”,第863行,开头
事件对=自执行轮询(轮询超时)
键盘中断
>>>>>>>>>获取用户配置文件链接(1,{'host':None,'port':None})
>>> 
>>> 
>>>io_loop.start()
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
文件“/usr/lib/python3.6/site packages/tornado/ioloop.py”,第755行,开头
raise RUNTIMERROR(“IOLoop已在运行”)
RuntimeError:IOLoop已在运行
>>>io_loop.stop()
>>>io_loop.start()
>>>io_loop.start()
工作
似乎io_loop.start()正在阻塞?我不认为是这样,这可能是问题所在。我现在必须重新考虑整个程序的架构。

一个未捕获的异常(在本例中是
键盘中断)使
IOLoop处于未定义状态。发生此类异常后,无法重新启动
IOLoop
(因为它可能在任何时候出现,并使
IOLoop
的内部不一致)。一般情况下,假设进程将在
键盘中断后退出。可以创建一个新的
IOLoop
并从头开始,但必须小心地重新创建依赖它的所有对象


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

您使用的是什么版本的python和tornado?ioloop是否正在另一个线程中运行?call_later不是线程安全的。Python 3.6是Tornado的最新版本。不知道你说的线程安全是什么意思。我没有对线程做任何特殊的处理。从Tornado的文档中,add_timeout(以后也适用于调用_)-:注意,从其他线程调用add_timeout是不安全的。相反,您必须使用add_回调将控制权转移到IOLoop的线程,然后从那里调用add_timeout。不过,这都在同一个线程中。如果不是,我会指定的。提供一步一步的例子。我运行的最简单的测试没有显示任何问题。我考虑了不同的线程,因为运行ioloop是阻塞的,并且问题中的上下文不清楚。
AsyncHTTPClient.configure("tornado.curl_httpclient.CurlAsyncHTTPClient")
http_client = AsyncHTTPClient()
http_client.max_clients = max_clients
http_client.request_timeout = request_timeout
"""...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()
$ 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