【问题标题】:Are there disadvantages of using channel.Get() over channel.Consume()?使用 channel.Get() 而不是 channel.Consume() 有缺点吗?
【发布时间】:2013-06-18 07:44:34
【问题描述】:

我正在使用streadway's amqp 库来连接rabbitmq 服务器。 该库提供了一个 channel.Consume() 函数,该函数返回一个“”。 它还提供了一个 channel.Get() 函数,该函数返回“Delivery”等内容。

我必须实现 pop() 功能,并且我正在使用 channel.Get()。但是,documentation 说:

"In almost all cases, using Channel.Consume will be preferred."

这里的首选是指推荐吗?在 channel.Consume() 上使用 channel.Get() 有什么缺点吗?如果是,如何使用 channel.Consume() 来实现 Pop() 函数?

【问题讨论】:

    标签: go rabbitmq amqp


    【解决方案1】:

    据我从文档中得知,是的,“首选”确实意味着“推荐”。

    似乎channel.Get() 没有提供与channel.Consume() 一样多的功能,并且由于它返回Deliverychan 而更容易在并发代码中使用,而不是每个单独的@ 987654330@单独。

    提到的额外功能是exclusivenoLocalnoWait,以及可选的参数Table“对队列或服务器具有特定语义”。

    要使用channel.Consume() 实现Pop() 函数,您可以链接到amqp example consumer 中的一些代码片段,创建一个channel using the Consume() function,创建一个function to handle the chan of Delivery,它实际上将实现您的Pop() 功能,然后fire off the handle() func in a goroutine

    关键是如果没有接收到,通道(在链接的示例中)将阻止发送。在示例中,handle() 函数使用range 处理整个通道,直到它为空。您的Pop() 功能可能会更好地由一个仅接收来自chan 的最后一个值并返回它的函数来提供。每次运行它都会返回最新的Delivery

    编辑:从通道接收最新值并对其进行处理的示例函数(这可能不适用于您的用例,如果该函数将另一个 Delivery 上的 Delivery 发送到另一个要处理的函数。另外,我没有测试过下面的代码,可能会出错)

    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
        }
    }
    

    【讨论】:

    • 非常感谢您的回复!但是,您的最后一行是我面临的确切问题。我尝试通过在传递通道上使用范围来创建 Pop(),但一旦找到值就会返回。当然,它返回了最新的值,但也从后台队列中弹出了所有其他值,所以我转到了 channel.Get()。我是频道和 goroutines 的新手。如何实现此功能以接收来自 chan 的最新值?
    【解决方案2】:

    这真的取决于你想做什么。如果您只想从队列中获取一条消息(第一条),您可能应该使用 basic.get,如果您打算处理来自队列的所有传入消息 - basic.consume 就是您想要的。

    可能不是平台或库特定的问题,而是协议理解问题。

    UPD

    我对 Go 语言不太熟悉,所以我会尝试为您简要介绍一下 AMQP 的详细信息并描述用例。

    您有时可能会遇到麻烦并使用basic.consume 产生开销:

    有了basic.consume,你就有了这样的工作流程:

    1. 发送basic.consume方法通知broker你要接收消息
      • 虽然这是一种同步方法,但请等待来自代理的 basic.consume-ok 消息
    2. 开始收听来自服务器的basic.deliver消息
      • 这是一种异步方法,您应该自己处理服务器上没有可用消息的情况,例如限制阅读时间

    有了basic.get,你就有了这样的工作流程:

    1. 发送同步方法basic.get给broker
      • 等待basic.get-ok 方法,它保存消息或basic.empty 方法,表示服务器上没有可用消息的情况

    关于同步和异步方法的注意事项:同步应该有一些响应,异步是否没有

    注意basic.qos 方法prefetch-count 属性:no-ack 属性设置在basic.consumebasic.get 上时,它会被忽略。

    规范在basic.get 上有一个注释:“此方法使用同步对话提供对队列中消息的直接访问,该同步对话专为同步功能比性能更重要的特定类型的应用程序而设计”,适用于连续消息消费。

    我的个人测试表明,在 RabbitMQ 3.0.1 和 Erlang R14B04 上,使用 basic.get (0.38659715652466) 获取 1000 条消息比使用 basic.consume 一条接一条 (0.47398710250854) 获取 1000 条消息要快 15% 以上.

    如果您只在主线程中使用一条消息 - 可能您必须使用basic.get

    您仍然可以只异步使用一条消息,例如在单独的线程中或使用某种事件机制。有时这对您的机器资源来说会是更好的解决方案,但您必须注意队列中没有可用消息的情况。

    如果你必须一一处理消息,很明显应该使用basic.consume,我认为

    【讨论】:

    • 我想要做的正是 basic.Get() 所做的,但我的问题是文档中的“首选”是否意味着“推荐”,即,即使我很富裕使用 Get(),文档是否仍然建议我应该使用 Consume() 而不是 Get()(因为 Get 本身的实现方式可能存在一些缺点等)?
    猜你喜欢
    • 2012-07-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-04
    • 2011-08-22
    • 2011-07-14
    相关资源
    最近更新 更多