如何在不阻止系统的情况下提供延迟AMP回复?

时间:2011-08-10 14:53:55

标签: python twisted

(我对提出更好的头衔很开心。)

我使用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回复?

1 个答案:

答案 0 :(得分:4)

您可能错过的一件事是AMP响应方法本身也允许返回延迟(搜索也可以在AMP API docs中返回Deferreds )。只要Deferred最终使用与命令的响应定义匹配的字典触发,一切都会正常工作。

同样有点相关,如果你想避免使用线程,你可能想看看twisted.internet.defer.DeferredQueue,一个本地知道Deferreds的队列数据结构。