如果回调花费的时间比callback_time长,则不会跳过Tornado periodiccallback调用

时间:2015-11-25 09:49:31

标签: python asynchronous tornado

考虑以下代码:

from tornado import ioloop, gen

@gen.coroutine
def test_callback():
    print 'entering test_callback'
    yield gen.sleep(10)
    print 'exiting test_callback'


if __name__ == '__main__':
    ioloop.PeriodicCallback(test_callback, 1000 * 5).start()
    ioloop.IOLoop.current().start()

这是输出:

entering test_callback
entering test_callback
entering test_callback
exiting test_callback
entering test_callback
exiting test_callback
entering test_callback
...

文档说如果回调需要更长时间,那么将跳过callback_time后续调用。但在这种情况下,这种情况并没有发生。我该怎么做才能确保仅在上一次回调调用完成后调用回调?

2 个答案:

答案 0 :(得分:1)

我在thread找到了解决方案。

基本上,如果回调占用更多,那么只有回调是同步的,才会跳过callback_time来执行后续调用。如果回调调用另一个异步例程,则PeriodicCallback无法知道所有将启动另一个回调调用。

在这种情况下,我们需要一个异步感知等效的PeriodicCallback:

from tornado import ioloop, gen

@gen.coroutine
def test_callback():
    print 'entering test_callback'
    yield gen.sleep(10)
    print 'exiting test_callback'

@gen.coroutine
def periodic():
    loop = ioloop.IOLoop.current()
    while True:
        start = loop.time()
        yield test_callback()
        duration = loop.time() - start
        yield gen.Task(loop.add_timeout, max(5 - duration, 0))

if __name__ == '__main__':
    ioloop.IOLoop.current().add_callback(periodic)
    ioloop.IOLoop.current().start()

这是输出:

entering test_callback
exiting test_callback
entering test_callback
exiting test_callback
entering test_callback
exiting test_callback
...

答案 1 :(得分:0)

也可以使用以下基于python 3.5的解决方案。

from tornado import ioloop, httpclient
class testCls:
  def __init__(self):
    self.n=0
    self.inProcess=False
  async def f1(self):
    url2='http://yoosofan.github.io/en/'
    http_client1 = httpclient.AsyncHTTPClient()
    response = await http_client1.fetch(url2)
    print('dd: ',self.n)
    self.n +=1
  async def my_function(self):
    print('z',end=' ')
    if self.inProcess==False:
    self.inProcess=True
    await self.f1()
    self.inProcess=False
if __name__ == '__main__':
  t1=testCls()
  ioloop.PeriodicCallback(t1.my_function, 60).start()
  ioloop.IOLoop.current().start()