Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/google-sheets/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 将芹菜用作扭曲应用程序的控制通道_Python_Twisted_Celery - Fatal编程技术网

Python 将芹菜用作扭曲应用程序的控制通道

Python 将芹菜用作扭曲应用程序的控制通道,python,twisted,celery,Python,Twisted,Celery,我试图使用芹菜作为扭曲应用程序的控制通道。我的Twisted应用程序是一个抽象层,它为各种本地运行的进程(通过ProcessProtocol)提供了一个标准接口。我想用芹菜来远程控制它——AMQP似乎是从一个中心位置控制许多Twisted应用程序的理想方法,我想利用芹菜的基于任务的功能,例如任务重试、子任务等 这并没有像我计划的那样有效,我希望有人能帮我找到正确的方向,让这一切顺利进行 当我运行脚本时,我试图实现的行为是: 开始一种稍加修饰的芹菜(参见 (见下文) 等待芹菜任务 收到“启动流程

我试图使用芹菜作为扭曲应用程序的控制通道。我的Twisted应用程序是一个抽象层,它为各种本地运行的进程(通过ProcessProtocol)提供了一个标准接口。我想用芹菜来远程控制它——AMQP似乎是从一个中心位置控制许多Twisted应用程序的理想方法,我想利用芹菜的基于任务的功能,例如任务重试、子任务等

这并没有像我计划的那样有效,我希望有人能帮我找到正确的方向,让这一切顺利进行

当我运行脚本时,我试图实现的行为是:

  • 开始一种稍加修饰的芹菜(参见 (见下文)
  • 等待芹菜任务
  • 收到“启动流程”任务后,生成一个ProcessProtocol
  • 当收到其他任务时,在Twisted协议上运行一个函数,并使用Deferreds返回结果
“稍微修改的celeryd”有一个小的修改,允许任务通过self.app.Twisted访问Twisted reactor,并通过self.app.process访问派生进程。为了简单起见,我使用了芹菜的“solo”流程池实现,它不会为任务工作者提供新的流程

当我尝试使用芹菜任务初始化ProcessProtocol(即启动外部进程)时,就会出现问题。进程正确启动,但从未调用ProcessProtocol的childDataReceived。我认为这与没有正确继承/设置文件描述符有关

下面是一些示例代码,基于ProcessProtocol文档中的“wc”示例。它包括两个芹菜任务——一个启动wc进程,另一个计算某些文本中的单词(使用先前启动的wc进程)

这个例子是精心设计的,但如果我能让它发挥作用,它将成为实现ProcessProtocols的一个很好的起点,ProcessProtocols是一个长期运行的进程,它将响应写入stdin的命令

我首先运行芹菜守护进程来测试这一点:

python2.6 mycelry.py-l信息-p单独

然后,在另一个窗口中,运行发送两个任务的脚本:

python2.6命令_test.py

command_test.py的预期行为是执行两个命令-一个启动wc进程,另一个向CountWordsTask发送一些文本。实际情况是:

  • StartProcTask生成进程,并通过一个不同的
  • CountWordsTask从未收到结果,因为从未调用childDataReceived
有没有人能解释一下这一点,或者就如何最好地使用芹菜作为TwistedProcessProtocols的控制通道提供一些建议

为芹菜编写Twisted backed ProcessPool实现会更好吗?我通过reactor.callLater从命令行调用WorkerCommand.execute\u的方法是否正确,可以确保所有事情都在Twisted线程中发生

我读过安瓿,我认为它可以提供一些这方面的功能,但如果可能的话,我想继续使用芹菜,因为我在我的应用程序的其他部分使用它

我们将非常感谢您的任何帮助

迈斯勒 protocol.py tasks.py
芹菜可能在等待来自网络的新消息时阻塞。由于您在一个单线程进程中与Twisted reactor一起运行它,因此它会阻止reactor运行。这将禁用大多数Twisted,这需要反应堆实际运行(您调用了
reactor.run
,但芹菜阻塞了它,它实际上没有运行)

reactor.callLater
只会延迟芹菜的启动。一旦芹菜开始生长,它仍然会阻塞反应堆

你需要避免的问题是阻塞反应堆

一种解决方案是在一个线程中运行芹菜,在另一个线程中运行反应器。使用
reactor.callFromThread
从芹菜线程向Twisted(“reactor线程中的调用函数”)发送消息。如果您需要从扭曲的线程向芹菜发送消息,请使用芹菜等价物


另一个解决方案是将芹菜协议(AMQP?-see)实现为本机Twisted库,并使用它来处理芹菜消息而不阻塞。

感谢你们两位花时间响应。哦,按下enter键太早了。谢谢你们两位花时间回复。你介意告诉我用这个方法从芹菜的线程中使用spawnProcess的最佳方法吗?我也需要通过callFromThread调用它吗?我已经使用txAMQP对此进行了概念验证,但我发现自己正在尝试复制芹菜的大部分功能,所以我想我会尝试直接从Twisted内部使用芹菜。这只是对将来尝试做类似事情的其他人的一个快速跟进。基于上述建议,我通过使用
reactor.callInThread(worker.execute\u from\u commandline)
启动芹菜,然后从芹菜任务代码中调用
blockingCallFromThread(reactor,reactor.spawnProcess,*args,**kwargs)
。我几乎让它完全按照计划工作——还有一个不同的问题需要解决,我已经准备好了。再次感谢Jean Paul和Glyph的帮助!为了完整起见,现在有一个在线程中运行Twisted reactor的库
from functools import partial
from celery.app import App
from celery.bin.celeryd import WorkerCommand
from twisted.internet import reactor


class MyCeleryApp(App):
    def __init__(self, twisted, *args, **kwargs):
        self.twisted = twisted
        super(MyCeleryApp, self).__init__(*args, **kwargs)

def main():
    get_my_app = partial(MyCeleryApp, reactor)
    worker = WorkerCommand(get_app=get_my_app)
    reactor.callLater(1, worker.execute_from_commandline)
    reactor.run()

if __name__ == '__main__':
    main()
from twisted.internet import protocol
from twisted.internet.defer import Deferred

class WCProcessProtocol(protocol.ProcessProtocol):

    def __init__(self, text):
        self.text = text
        self._waiting = {} # Dict to contain deferreds, keyed by command name

    def connectionMade(self):
        if 'startup' in self._waiting:
            self._waiting['startup'].callback('process started')

    def outReceived(self, data):
        fieldLength = len(data) / 3
        lines = int(data[:fieldLength])
        words = int(data[fieldLength:fieldLength*2])
        chars = int(data[fieldLength*2:])
        self.transport.loseConnection()
        self.receiveCounts(lines, words, chars)

        if 'countWords' in self._waiting:
            self._waiting['countWords'].callback(words)

    def processExited(self, status):
        print 'exiting'


    def receiveCounts(self, lines, words, chars):
        print >> sys.stderr, 'Received counts from wc.'
        print >> sys.stderr, 'Lines:', lines
        print >> sys.stderr, 'Words:', words
        print >> sys.stderr, 'Characters:', chars

    def countWords(self, text):
        self._waiting['countWords'] = Deferred()
        self.transport.write(text)
        return self._waiting['countWords']
from celery.task import Task
from protocol import WCProcessProtocol
from twisted.internet.defer import Deferred
from twisted.internet import reactor

class StartProcTask(Task):
    def run(self):
        self.app.proc = WCProcessProtocol('testing')
        self.app.proc._waiting['startup'] = Deferred()
        self.app.twisted.spawnProcess(self.app.proc,
                                      'wc',
                                      ['wc'],
                                      usePTY=True)
        return self.app.proc._waiting['startup']

class CountWordsTask(Task):
    def run(self):
        return self.app.proc.countWords('test test')