2013-04-21 61 views
3

我想在龙卷风主循环中添加多个回调。但是,当我运行此代码:如何在龙卷风中创建多个add_callback?

def task(num): 
    print 'task %s' % num 

if __name__ == '__main__': 
    for i in range(1,5): 
     tornado.ioloop.IOLoop.instance().add_callback(callback=lambda: task(num=i)) 
    tornado.ioloop.IOLoop.instance().start() 

我得到的输出5倍: '任务5',而不是任务1 ...任务5. 当我改变主要这样的:

tornado.ioloop.IOLoop.instance().add_callback(callback=lambda: task(1)) 
tornado.ioloop.IOLoop.instance().add_callback(callback=lambda: task(2)) 
tornado.ioloop.IOLoop.instance().add_callback(callback=lambda: task(3)) 
tornado.ioloop.IOLoop.instance().add_callback(callback=lambda: task(4)) 

一切工作正常(我得到输出task1-task5)。第一种情况我做错了什么?

+1

拉姆达封闭是建立在'i'和它结束up为5 – thkang 2013-04-21 09:12:50

回答

1

也许有像JS一样的问题? 看这个问题:JavaScript closure inside loops – simple practical example

“问题在于变量i,在你的每个匿名函数中,被绑定到函数外的同一个变量。”

尝试简单的测试:

def task(num): 
    print 'task %s' % num 

def create_task(num): 
    tornado.ioloop.IOLoop.instance().add_callback(callback=lambda: task(num)) 

if __name__ == '__main__': 
    for i in range(1,5): 
     create_task(i) 
    tornado.ioloop.IOLoop.instance().start() 
+0

是的,你是对的。最简单的解决方法是:tornado.ioloop.IOLoop.instance()。add_callback(callback = lambda i = i:task(i)) – DukeLog 2013-04-21 12:56:53

1

包装你的λ为functools.partial()功能,解决了 “指针问题” IOLoop.instance().add_callback(callback=functools.partial(task, i*10))

TL;博士;

这里是用“指针问题” BUG一个例子:在高于i代码示例

def task(num): 
    print(num) 

for i in range(1, 6): 
    print ("poop {0}".format(i)) 
    IOLoop.instance().add_callback(callback=lambda: task(i)) 
IOLoop.instance().start() 

将是一个存储器指针值range()当前迭代上。它从1变为2,然后变为3,4,5。

Tornado的add_callback()异步函数将控制权立即返回给主程序,使所有5个对task()函数的调用几乎同时执行。并且此时i已获得5的值。

为了解决这个问题,快速地使用funtools.partial函数而不是拉姆达和研究的区别;)

这里是没有错误的例子:

IOLoop.instance().add_callback(callback=functools.partial(task, i*10))