3

我正在尝试在龙卷风主循环中添加多个回调。但是当我运行这段代码时:

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 次:'task 5',而不是 task 1.. task 5。当我像这样更改main时:

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)。在第一种情况下我做错了什么?

4

2 回答 2

1

也许在 JS 中也有同样的问题?看看这个答案:循环内的 JavaScript 闭包——简单实用的例子

“问题是每个匿名函数内的变量 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()
于 2013-04-21T09:36:23.037 回答
1

将您的 lambda 包装到functools.partial()解决“指针问题”的函数中 IOLoop.instance().add_callback(callback=functools.partial(task, i*10))

tl;博士;

这是一个带有“指针问题”BUG的例子:

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()

在上面的代码示例中,i将是一个指向range()当前迭代值的内存指针。它从 1 变为 2,然后变为 3、4、5。

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

要快速解决此问题,请使用funtools.partial函数而不是 lambda 并研究差异;)

这是无 BUG 的示例:

IOLoop.instance().add_callback(callback=functools.partial(task, i*10))
于 2017-04-20T22:19:02.903 回答