- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我有两个独立的 RabbitMQ 实例。我正试图找到最好的方式来收听来自两者的事件。
例如,我可以使用以下方式消费事件:
credentials = pika.PlainCredentials(user, pass)
connection = pika.BlockingConnection(pika.ConnectionParameters(host="host1", credentials=credentials))
channel = connection.channel()
result = channel.queue_declare(Exclusive=True)
self.channel.queue_bind(exchange="my-exchange", result.method.queue, routing_key='*.*.*.*.*')
channel.basic_consume(callback_func, result.method.queue, no_ack=True)
self.channel.start_consuming()
我有第二个主持人,“host2”,我也想听听。我考虑过创建两个单独的线程来执行此操作,但据我所知,鼠兔不是线程安全的。有没有更好的办法?或者创建两个单独的线程,每个线程监听不同的 Rabbit 实例(host1 和 host2)就足够了吗?
最佳答案
“什么是最好的方法”的答案在很大程度上取决于您的队列使用模式以及“最佳”的含义。由于我还不能对问题发表评论,我只会尝试提出一些可能的解决方案。
在每个示例中,我都假设交换已经声明。
您可以使用 pika
在单个进程中使用来自不同主机上的两个队列的消息.
你是对的 - 作为 its own FAQ states , pika
不是线程安全的,但它可以通过为每个线程创建到 RabbitMQ 主机的连接以多线程方式使用。使用 threading
使此示例在线程中运行模块如下所示:
import pika
import threading
class ConsumerThread(threading.Thread):
def __init__(self, host, *args, **kwargs):
super(ConsumerThread, self).__init__(*args, **kwargs)
self._host = host
# Not necessarily a method.
def callback_func(self, channel, method, properties, body):
print("{} received '{}'".format(self.name, body))
def run(self):
credentials = pika.PlainCredentials("guest", "guest")
connection = pika.BlockingConnection(
pika.ConnectionParameters(host=self._host,
credentials=credentials))
channel = connection.channel()
result = channel.queue_declare(exclusive=True)
channel.queue_bind(result.method.queue,
exchange="my-exchange",
routing_key="*.*.*.*.*")
channel.basic_consume(self.callback_func,
result.method.queue,
no_ack=True)
channel.start_consuming()
if __name__ == "__main__":
threads = [ConsumerThread("host1"), ConsumerThread("host2")]
for thread in threads:
thread.start()
我已将 callback_func
声明为一种纯粹用于在打印消息正文时使用 ConsumerThread.name
的方法。它也可能是 ConsumerThread
类之外的函数。
或者,您始终可以只为每个要使用事件的队列运行一个带有使用者代码的进程。
import pika
import sys
def callback_func(channel, method, properties, body):
print(body)
if __name__ == "__main__":
credentials = pika.PlainCredentials("guest", "guest")
connection = pika.BlockingConnection(
pika.ConnectionParameters(host=sys.argv[1],
credentials=credentials))
channel = connection.channel()
result = channel.queue_declare(exclusive=True)
channel.queue_bind(result.method.queue,
exchange="my-exchange",
routing_key="*.*.*.*.*")
channel.basic_consume(callback_func, result.method.queue, no_ack=True)
channel.start_consuming()
然后运行:
$ python single_consume.py host1
$ python single_consume.py host2 # e.g. on another console
如果您对来自队列的消息所做的工作是 CPU-heavy并且只要您的 CPU 中的内核数量 >= 消费者数量,通常最好使用这种方法 - 除非您的队列大部分时间都是空的并且消费者不会利用此 CPU 时间*。
另一种选择是涉及一些异步框架(例如 Twisted
)并在单线程中运行整个过程。
您不能再在异步代码中使用 BlockingConnection
;幸运的是,pika
有 Twisted
的适配器:
from pika.adapters.twisted_connection import TwistedProtocolConnection
from pika.connection import ConnectionParameters
from twisted.internet import protocol, reactor, task
from twisted.python import log
class Consumer(object):
def on_connected(self, connection):
d = connection.channel()
d.addCallback(self.got_channel)
d.addCallback(self.queue_declared)
d.addCallback(self.queue_bound)
d.addCallback(self.handle_deliveries)
d.addErrback(log.err)
def got_channel(self, channel):
self.channel = channel
return self.channel.queue_declare(exclusive=True)
def queue_declared(self, queue):
self._queue_name = queue.method.queue
self.channel.queue_bind(queue=self._queue_name,
exchange="my-exchange",
routing_key="*.*.*.*.*")
def queue_bound(self, ignored):
return self.channel.basic_consume(queue=self._queue_name)
def handle_deliveries(self, queue_and_consumer_tag):
queue, consumer_tag = queue_and_consumer_tag
self.looping_call = task.LoopingCall(self.consume_from_queue, queue)
return self.looping_call.start(0)
def consume_from_queue(self, queue):
d = queue.get()
return d.addCallback(lambda result: self.handle_payload(*result))
def handle_payload(self, channel, method, properties, body):
print(body)
if __name__ == "__main__":
consumer1 = Consumer()
consumer2 = Consumer()
parameters = ConnectionParameters()
cc = protocol.ClientCreator(reactor,
TwistedProtocolConnection,
parameters)
d1 = cc.connectTCP("host1", 5672)
d1.addCallback(lambda protocol: protocol.ready)
d1.addCallback(consumer1.on_connected)
d1.addErrback(log.err)
d2 = cc.connectTCP("host2", 5672)
d2.addCallback(lambda protocol: protocol.ready)
d2.addCallback(consumer2.on_connected)
d2.addErrback(log.err)
reactor.run()
这种方法会更好,您消耗的队列越多,消费者执行的工作对 CPU 的限制就越少*。
既然你提到了 pika
,我将自己限制在基于 Python 2.x 的解决方案上,因为 pika
尚未移植。
但是如果你想移动到 >=3.3,一个可能的选择是使用 asyncio
使用 AMQP 协议(protocol)之一(您与 RabbitMQ 交谈的协议(protocol)),例如asynqp
或 aioamqp
.
* - 请注意,这些都是非常肤浅的技巧 - 在大多数情况下,选择并不那么明显;什么对你最好取决于队列“饱和度”(消息/时间),你在收到这些消息后做了什么工作,你在什么环境中运行你的消费者等等;除了对所有实现进行基准测试外,没有其他方法可以确定
关于Python 和 RabbitMQ - 收听来自多个 channel 的消费事件的最佳方式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28550140/
我很好奇为什么以下不起作用。一般select用default:防止死锁,但在这种情况下不是: package main import "fmt" func main () { a := mak
我一生都无法弄清楚如何切换图像排序。图像以 (x,x,3) 格式读取,theano 要求它是 (3,x,x) 格式。我尝试更改顺序numpy.array([img[:,:,i] for i in ra
我正在向 libnl 发送单个 SSID 和频率进行扫描,但我得到了多个扫描结果以及我请求的 SSID 和频率,但我需要单个扫描结果(仅适用于请求的 SSID),如何实现这一点。请帮助我,我也发送了我
我是 Golang 的新手,但正在努力理解这门伟大的语言!请帮帮我.. 我有 2 个 channel 。 “进”和“出” channel in, out := make(chan Work),
例如我有这段代码: package main import ( "fmt" ) func main() { c1 := make(chan interface{}) close
我们使用以下调用来获取经过身份验证的用户的 ChannelID,它适用于大多数情况。一些 YouTube 用户将他们的 channel 连接到 Google+ 信息页,但在这种情况下,我们的一位用户无
case 'sinfo': const sinfo = new Discord.MessageEmbed() .addField('Server Name 🔎 :', message.guild.n
我需要让所有 channel 来创建一个 bunker 命令,这使得所有 channel 都是只读的。 最佳答案 他们变了Client.servers至 Client.guilds在 newer ve
为什么当第二个值通过另一个 go routine 发送并且没有收到发送的第一个值时, channel c 没有缓冲? package main import "fmt" func sum(s []in
据我所知,内置的 split 会将一个 3 channel Mat 拆分为三个 1 channel Mat。结果,这三个 Mat 只是具有一些不同强度的灰度。 我的意图是获得三个 3 channel
如何检测当前的 RAM 配置?我需要询问 Windows RAM 当前是在单 channel 、双 channel 还是四 channel 中运行。 我搜索了很多,并没有在这个网站或其他网站上找到任何
我需要拆分一个多 channel wav 文件并将每个 channel 编码为 mp3 文件。 我知道 gtresamer 的 deinterleave 插件,但我不确定如何将它用于 wav 文件以及
关闭。这个问题需要details or clarity .它目前不接受答案。 想要改进这个问题吗? 通过 editing this post 添加详细信息并澄清问题. 关闭 8 年前。 Improve
我正在尝试运行 Hyperledger Fabric 网络,它由单个订购者、单个对等节点和一个 cli 组成。为了学习启动 Hyperledger Fabric 网络的过程,从创建与加密相关的工件到将
我在 Laravel 中使用事件广播。我正在使用基于角色的通知访问权限。我有用于广播的自定义 auth guard。当用户连接到 channel 时,客户端将具有内部权限的 access_token
我正在编写一个使用 Elixir Channels 来处理实时事件的应用程序。我知道每个客户端将打开 1 个套接字,并且可以在其上多路复用多个 channel 。所以我的应用程序是一个聊天应用程序,其
我有一些 .wav 文件,我想转换它们的频率 (fs) 和 channel 数 (nchannels)。我在jupyter笔记本python3.6上使用ffmpeg。我使用了以下命令并且它有效。 cm
我有一个视频渲染器,它需要两个 H265 流(YUV420),我需要烘焙它们以使它们中的一个与另一个形成 alpha 蒙版。这一切都已解决并且效果很好,但是如果我按照此处的说明进行操作: ffmpeg
我运行此命令以便能够将 udp 直播流传输到可使用正在构建的移动应用程序播放的 http 直播流。 它只是一个只有音频流的流。 ffmpeg -i udp://@localhost:1111 -map
我在我的 discord.js 机器人中创建了 nuke 命令,它创建了具有相同名称、权限、主题等的 channel ,并删除了“原始” channel 。但是有一个问题,如何使 channel 与“
我是一名优秀的程序员,十分优秀!