我有一种感觉,这真的不是那么困难,但到目前为止,我几乎没有成功。
假设我有一个名为PikaClass的类,它包装了pika并提供了一些业务方法。
def PikaClass(object):
def __init__(self):
# connect to the broker
self.connection = pika.SelectConnection(<connection parameters>, self.on_connect)
# ..other init stuff..
def on_connect(self, connection):
# called when the connection has been established
# ..open a channel, declare some queues, etc.
def start(self):
# start the polling loop
self.connection.ioloop.start()
def foo(self, **kwargs):
# do some business logic, e.g., send messages to particular queues直观地说,这就是我想要实现的目标:用户创建一个PikaClass实例,在后台设置循环,然后通过调用某些业务方法与对象进行交互
p = PikaClass()
p.start()
bar = p.foo(..)问题是一旦调用了start(),p.start()就会阻塞并阻止主代码与对象交互。我的第一个想法是将调用封装在一个线程中:
Thread(target=p.start()).start()
bar = p.foo(..)但这仍然会阻塞,并且您永远不会到达p.foo(..)。文档中提到,您不应该在线程之间共享连接,因此这可能会在某个地方导致问题。
我还尝试使用AsyncoreConnection而不是SelectConnection,并直接调用_connect() (而不是使用ioloop),但没有任何效果(什么都没有发生)。
那么我如何在后台运行ioloop,或者至少运行我自己的ioloop呢?
注意:这是win64 (xp)上的Python2.6,带有最新的pika 0.9.4
发布于 2011-05-03 09:54:17
GIL在这里不是问题,因为ioloop几乎所有的时间都花在select(2)系统调用中,在此期间GIL被释放,其他Python线程可以运行并执行其他任务。
最简单的方法是为每个请求建立并拆除一个队列连接。您可能认为这太昂贵了-因为它需要重新验证,并且(可能)对每个连接重复SSL协商-但它应该是最简单、最健壮和最容易编写的,这应该是您的控制因素,除非您知道设置和拆卸实际上会损害应用程序的整体性能(最好通过测试来衡量)。
另一种方法是,只有在有消息要发送时才start() ioloop,然后让接收回复的方法停止ioloop,这样您的程序就可以再次获得控制权。您可以使用以下命令使ioloop提前返回:
connection.ioloop.poller.open = False然后记得在再次调用start()等待另一个响应之前将其设置回True。
发布于 2012-07-27 23:39:20
您正在调用“p.start”,而不是将其作为参数传递。代码应该是:
Thread(target=p.start).start()执行Thread.start时,线程将调用p.start。
我不确定这是否会解决你的问题,但它可能会帮助你找到解决方案。
发布于 2011-03-11 22:11:34
你可能需要第二个进程,我不太了解pika,但如果它是纯python,那么它会想要保留GIL -记住,无论你有多少内核,每个进程一次只能执行一个线程,这是由于python出色的垃圾收集所使用的引用计数器的限制。
如果您在if __name__ == "__main__":块中执行/anything/ else操作之前启动了一个新进程,并将其设置为等待循环中的事件,则可以向第二个进程发送执行某项工作的指令,然后等待它将结果发回给您。您可能希望实现某种类型的索引系统,这样您就可以将您的工作发送到另一个进程,并在需要答案之前忘记它。
我给你的唯一建议是避免副作用,否则你将不得不考虑竞态条件、死锁和GIL保护你免受的所有其他可怕的事情。在进程开始之前向它发送所需的信息,或者确保在它要求您提供该数据之前没有对其进行修改。
这是为数不多的几种情况中的一种,在这种情况下,Python会把枪递给你,只是礼貌地说不要把枪对准你的脚。
https://stackoverflow.com/questions/5273686
复制相似问题