(我对提出更好的头衔很开心。)
我使用AMP协议而非Twisted来创建一个调度程序,将作业输出到其代理。代理程序从调度程序中提取作业,因此调度程序是AMP服务器,代理程序作为客户端连接。
这个想法是让代理连接,从(内部调度程序)作业队列的顶部获取作业,然后继续执行它的方式。但是,不保证该队列始终为非空。因此,我希望利用扭曲的延迟机制,以便在调度程序设法从队列中弹出作业时,在代理程序端简单地发生延迟激活。
然而,在调度程序端实现这一点有点棘手。 AMP的工作方式是为代理可以发送的每个(由我预定义)命令分配一个函数,该函数获取该命令具有的所有参数,并返回它返回的所有值的字典。这意味着我需要在一个函数中完成所有这些操作。通常,这不会是一个问题,但这里扭曲似乎妨碍了我:我需要让函数暂停一点,而不会暂停扭曲的事件循环,从而允许它实际上向队列添加更多的作业,所以一个可以弹出。 (这就是我不认为通常的sleep()
会产生预期效果的原因。)更重要的是,这意味着我无法想到使用某些扭曲功能的方法,例如: deferToThread()
,因为我必须在我将指定为deferred
的回调的单独函数中处理结果(并且只能访问它们),所以我不知道是什么在启动单独的线程并分配其回调后返回AMP响应器功能。这更清楚地说明了我的意思:
def assignJob(agentID):
# We expect the agentID, so we can store who we've given a job to.
# Get a job without blocking even if the queue is originally empty.
job = None
while job is None:
try:
job = jobqueue.pop(0)
except IndexError:
# Imagine getJob simply tries to get a job every 5 seconds
# (using sleep() safely because it's in a separate thread)
# until it eventually gets one, which it returns
d = deferToThread(getJob)
# We would then need to have a separate function
# , e.g. jobReturn() pick up the firing deferred and do
# something with the result...
d.addCallback(jobReturn)
# But if we do... We don't (necessarily) have a job to return here
# because for all we know, the deferred from that thread hasn't even
# fired yet.
return {'job': ???}
(这显然不是该函数的实际完整代码 - 例如,它是amp.AMP
子类的一种方法。)
反应器方法callInThread()
一开始似乎也很有用(因为它不会返回延迟),但它没有提供获取它执行的可调用的返回值的方法(至于我可以看到),即使它确实如此,这意味着等待线程完成,这会阻止这个方法一段时间,这使得使用一个单独的线程毫无意义。
那么在我有工作之前如何阻止这种方法,但是不是整个Twisted事件循环,或者,如何在其立即响应方法之外返回AMP回复?
答案 0 :(得分:4)
您可能错过的一件事是AMP响应方法本身也允许返回延迟(搜索也可以在AMP API docs中返回Deferreds )。只要Deferred最终使用与命令的响应定义匹配的字典触发,一切都会正常工作。
同样有点相关,如果你想避免使用线程,你可能想看看twisted.internet.defer.DeferredQueue,一个本地知道Deferreds的队列数据结构。