Python Twisted - 运行多个回调

时间:2016-04-07 22:27:42

标签: python asynchronous callback twisted

我很擅长扭曲,我真的需要一件事 - 运行任意数量的函数(从相同的驯服开始),从所有函数中收集结果并进行一些处理。

这就是我所拥有的:

from twisted.internet import defer
import time


# slow computing query
def process_data(num, data):
    time.sleep(5)
    array = []
    # mock the results obtained from processed data
    for i in range(0, 5):
        array.append(num)
    return array

def process_results(arrays):
    # this should collect return arrays of all callbacks 
    print arrays

data = []
callbacks_refs = []
for i in range(0, 5):
   d=defer.Deferred()
   d.addCallback(process_data)
   callbacks_refs.append(d)

callbacks = defer.DeferredList(callbacks_refs)
callbacks.addCallback(process_results)

for i, d in enumerate(callbacks_refs):
    d.callback(i, data)

我希望最后一个for循环将异步启动所有回调的执行(就像通常使用Promises一样)并且所有结果都将传递给process_results函数,该函数将在callbacks_refs的所有回调完成后执行,但是我觉得我非常错误。

2 个答案:

答案 0 :(得分:2)

我不知道您的示例与您的实际代码有多接近,但示例代码显示了对Twisted所做的一些误解。 Twisted并没有神奇地使你的同步代码异步。您正在阻止time.sleep中的事件循环。如果你正在做一些CPU绑定(而不是I / O绑定),你可以使用多个线程或进程。

我将假设process_data是一个阻塞调用,并为您提供基于多线程的解决方案:

import time
from twisted.internet import defer, task, threads

# slow computing query
def process_data(num):
    time.sleep(5)
    array = []
    # mock the results obtained from processed data
    for i in range(0, 5):
        array.append(num)
    return array

def process_results(arrays):
    # this should collect return arrays of all callbacks
    print arrays

def main(_):
    callbacks_refs = []
    for i in range(0, 5):
        callbacks_refs.append(threads.deferToThread(process_data, i))
    callbacks = defer.DeferredList(callbacks_refs)
    callbacks.addCallback(process_results)
    return callbacks

task.react(main)

我还会给你一个关于Twisted编程的一般建议 - 如果你发现自己输入了d = defer.Deferred(),你的设计可能会出现问题。

答案 1 :(得分:0)

我不知道这是否有解决方法,但是根据您defer.callback()的方式,您将获得传递给回调的错误参数。

如果你要附加一个错误回复和一个回调,你可能会发现你只是得到了大量失败的结果......所以它的工作,但没有按预期工作。

我看到两个修复。

from functools import partial
for i in range(0, 5):
    d=defer.Deferred()
    d.addCallback(partial(process_data,i,data[i]))
    # This partial is still kinda crooked, but hopefully I have made my point
    callbacks_refs.append(d)

或更改在回调函数中传递数据的方式

# slow computing query
def process_data(data_dict):
    #data_dict['num']
    #data_dict['data']

#...and further down
d.callback({'num':4,'data':(1,2,3)})

对不起,我对deferredlist不太熟悉,但我认为一旦你修复了延期,延期列表可能会自动运行。