英文:
Are there disadvantages of using channel.Get() over channel.Consume()?
问题
我正在使用streadway的amqp库与rabbitmq服务器进行连接。
该库提供了一个channel.Consume()函数,它返回一个"<- chan Delivery"。
它还提供了一个channel.Get()函数,其中包括一个"Delivery"等其他内容。
我需要实现一个pop()功能,并且我正在使用channel.Get()。然而,文档中说:
"在几乎所有情况下,使用Channel.Consume将被优先选择。"
这里的preferred是否意味着recommended?使用channel.Get()而不是channel.Consume()有什么缺点吗?如果有,我如何使用channel.Consume()来实现Pop()函数?
英文:
I'm using streadway's amqp library to connect with a rabbitmq server.
The library provides a channel.Consume() function which returns a "<- chan Delivery".
It also provides a channel.Get() function which returns a "Delivery" among other things.
I've to implement a pop() functionality, and I'm using channel.Get(). However, the documentation says:
"In almost all cases, using Channel.Consume will be preferred."
Does the preferred here means recommended? Are there any disadvantages of using channel.Get() over channel.Consume()? If yes, how do I use channel.Consume() to implement a Pop() function?
答案1
得分: 6
根据文档,据我所知,“preferred”确实意味着“推荐”。
从文档中可以看出,channel.Get()
提供的功能没有channel.Consume()
多,并且由于返回的是chan
类型的Delivery
,而不是每个单独的Delivery
,因此在并发代码中更容易使用。
提到的额外功能包括exclusive
、noLocal
和noWait
,以及一个可选的Table
参数,它们对队列或服务器具有特定的语义。
要使用channel.Consume()
实现一个Pop()
函数,你可以参考amqp示例消费者中的一些代码片段,创建一个使用Consume()
函数的channel,创建一个处理chan
类型的Delivery
的函数,该函数实际上会实现你的Pop()
功能,然后在一个goroutine
中启动handle()
函数。
关键在于,通道(在示例中)在没有接收方时会阻塞发送。在示例中,handle()
函数使用range
来处理整个通道,直到它为空。你的Pop()
功能可能更适合使用一个函数,该函数只接收chan
中的最后一个值并返回它。每次运行时,它都会返回最新的Delivery
。
编辑:以下是一个示例函数,用于接收通道中的最新值并对其进行处理(这可能对你的用例不起作用,如果该函数将Delivery
发送到另一个chan
以供另一个函数处理可能更有用。此外,我没有测试下面的代码,可能会有错误)。
func handle(deliveries <-chan amqp.Delivery, done chan error) {
select {
case d := <-deliveries:
// 处理delivery
// 将任何错误发送到done chan。例如:
// done <- err
default:
done <- nil
}
}
英文:
As far as I can tell from the docs, yes, "preferred" does mean "recommended".
It seems that channel.Get()
doesn't provide as many features as channel.Consume()
, as well as being more readily usable in concurrent code due to it's returning a chan
of Delivery
, as opposed to each individual Delivery
separately.
The extra features mentioned are exclusive
, noLocal
and noWait
, as well as an optional Table
of args "that have specific semantics for the queue or server."
To implement a Pop()
function using channel.Consume()
you could, to link to some code fragments from the amqp example consumer, create a channel using the Consume()
function, create a function to handle the chan
of Delivery
which will actually implement your Pop()
functionality, then fire off the handle()
func in a goroutine
.
The key to this is that the channel (in the linked example) will block on sending if nothing is receiving. In the example, the handle()
func uses range
to process the entire channel until it's empty. Your Pop()
functionality may be better served by a function that just receives the last value from the chan
and returns it. Every time it's run it will return the latest Delivery
.
EDIT: Example function to receive the latest value from the channel and do stuff with it (This may not work for your use case, it may be more useful if the function sent the Delivery
on another chan
to another function to be processed. Also, I haven't tested the code below, it may be full of errors)
func handle(deliveries <-chan amqp.Delivery, done chan error) {
select {
case d = <-deliveries:
// Do stuff with the delivery
// Send any errors down the done chan. for example:
// done <- err
default:
done <- nil
}
}
答案2
得分: 6
这真的取决于你想要做什么。如果你只想从队列中获取一条消息(第一条),你可能应该使用basic.get
,如果你计划处理队列中的所有传入消息,那么basic.consume
就是你想要的。
可能这不是一个特定于平台或库的问题,而是一个协议理解的问题。
更新
我对Go语言不太熟悉,所以我会尝试给你一些关于AMQP细节的简要说明并描述使用情况。
有时候使用basic.consume
可能会遇到一些麻烦和额外的开销:
使用basic.consume
的工作流程如下:
- 发送
basic.consume
方法通知代理你想要接收消息- 虽然这是一个同步方法,但要等待来自代理的
basic.consume-ok
消息
- 虽然这是一个同步方法,但要等待来自代理的
- 开始监听来自服务器的
basic.deliver
消息- 这是一个异步方法,你需要自己处理服务器上没有可用消息的情况,例如限制读取时间
使用basic.get
的工作流程如下:
- 发送同步方法
basic.get
给代理- 等待
basic.get-ok
方法,其中包含消息或basic.empty
方法,表示服务器上没有可用的消息
- 等待
*关于同步和异步方法的说明:*同步方法预期会有一些响应,而异步方法则没有
*关于basic.qos
方法的prefetch-count
属性的说明:*当在basic.consume
或basic.get
上设置了no-ack
属性时,它会被忽略。
规范对basic.get
有一个注释:“该方法提供了一种直接访问队列中消息的方式,使用同步对话,适用于同步功能比性能更重要的特定类型的应用程序”,这适用于连续消息消费。
我的个人测试显示,在RabbitMQ 3.0.1,Erlang R14B04上,使用basic.get
连续获取1000条消息(0.38659715652466)比使用basic.consume
逐条获取1000条消息(0.47398710250854)平均快15%以上。
如果只在主线程中消费一条消息是你的情况,可能你需要使用basic.get
。
你仍然可以异步地消费一条消息,例如在单独的线程中或使用某种事件机制。这对于你的机器资源来说可能是更好的解决方案,但你必须注意队列中没有可用消息的情况。
如果你必须逐条处理消息,那么显然应该使用basic.consume
,我认为。
英文:
It really depend of what are you trying to do. If you want to get only one message from queue (first one) you probably should use basic.get
, if you are planning to process all incoming messages from queue - basic.consume
is what you want.
Probably, it is not platform or library specific question but rather protocol understanding question.
UPD
I'm not familiar with it go language well, so I will try to give you some brief on AMQP details and describe use cases.
You may get in troubles and have an overhead with basic.consume
sometimes:
With basic.consume
you have such workflow:
- Send
basic.consume
method to notify broker that you want to receive messages
- while this is a synchronous method, wait for
basic.consume-ok
message from broker
- Start listening to
basic.deliver
message from server
- this is an asynchronous method and you should take care by yourself situations where no messages on server available, e.g. limit reading time
With basic.get
you have such workflow:
- send synchronous method
basic.get
to broker
- wait for
basic.get-ok
method, which hold message(s) orbasic.empty
method, which denote situation no message available on server
Note about synchronous and asynchronous methods: synchronous is expected to have some response, whether asynchronous doesn't
Note on basic.qos
method prefetch-count
property: it is ignored when no-ack
property is set on basic.consume
or basic.get
.
Spec has a note on basic.get
: "this method provides a direct access to the messages in a queue using a synchronous dialogue that is designed for specific types of application where synchronous functionality is more important than performance" which applies for continuous messages consumption.
My personal tests show that getting in row 1000 messages with basic.get
(0.38659715652466) is faster than getting 1000 messages with basic.consume
one by one (0.47398710250854) on RabbitMQ 3.0.1, Erlang R14B04 in average more than 15%.
If consume only one message in main thread is your case - probably you have to use basic.get
.
You still can consume only one message asynchronously, for example in separate thread or use some event mechanism. It would be better solution for you machine resource sometimes, but you have to take care about situation where no message available in queue.
If you have to process message one by one it is obvious that basic.consume
should be used, I think
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论