C# 如何利用.NET RabbitMQ客户端的使用者预取计数

C# 如何利用.NET RabbitMQ客户端的使用者预取计数,c#,rabbitmq,messaging,C#,Rabbitmq,Messaging,其在RabbitMQ文件中声明如下: 根据经验,在线程之间共享通道实例是非常重要的 需要避免的事情。应用程序应该更喜欢使用通道 每个线程,而不是跨多个线程共享同一通道 线程。” 目前,我们正在查看预回迁计数,其中建议,如果您有少量消费者且autoack=false,那么我们应该一次消费多条消息。但是,我们发现,如果使用者使用单个执行线程将手动确认发送回,则预回迁无效。但是,如果我们将使用者处理封装在一个任务中,我们会发现预取计数确实很重要,并且会显著提高使用者性能 请参见以下示例,其中我们将消费

其在RabbitMQ文件中声明如下:

根据经验,在线程之间共享通道实例是非常重要的 需要避免的事情。应用程序应该更喜欢使用通道 每个线程,而不是跨多个线程共享同一通道 线程。”

目前,我们正在查看预回迁计数,其中建议,如果您有少量消费者且autoack=false,那么我们应该一次消费多条消息。但是,我们发现,如果使用者使用单个执行线程将手动确认发送回,则预回迁无效。但是,如果我们将使用者处理封装在一个任务中,我们会发现预取计数确实很重要,并且会显著提高使用者性能

请参见以下示例,其中我们将消费者对消息的使用包装到任务对象中:

class Program
{
    public static void Main()
    {
        var factory = new ConnectionFactory()
        {
            HostName = "172.20.20.13",
            UserName = "billy",
            Password = "guest",
            Port = 5671,
            VirtualHost = "/",
            Ssl = new SslOption
            {
                Enabled = true,
                ServerName = "rabbit.blah.com",
                Version = System.Security.Authentication.SslProtocols.Tls12
            }
        };
        var connection = factory.CreateConnection();
        var channel = connection.CreateModel();
        channel.BasicQos(0, 100, false);
        channel.ExchangeDeclare(exchange: "logs", type: "fanout");
        var queueName = channel.QueueDeclare().QueueName;
        Console.WriteLine(" [*] Waiting for logs.");

        var consumer = new EventingBasicConsumer(channel);
        consumer.Received += (model, ea) =>
        {
            var _result = new Task(() => {
                var body = ea.Body;
                var message = Encoding.UTF8.GetString(body);
                System.Threading.Thread.Sleep(80);

                channel.BasicAck(ea.DeliveryTag, false);
            });
            _result.Start();
        };
        channel.BasicConsume(queue: "test.queue.1", autoAck: false, consumer: consumer);

        Console.WriteLine(" Press [enter] to exit.");
        Console.ReadLine();
    }
}
我的问题是,人们如何使用.NET rabbitmq客户端实现利用预取计数的消费者?您是否必须使用某种任务手动确认?是否安全来源:

使用手动确认时,重要的是考虑。 确认的线索是什么。如果它与 接收交付的线程(例如,消费者处理交付 将交付处理委托给不同的线程),通过 设置为true的多参数不安全,将导致 双重确认,因此是通道级协议 关闭通道的异常。一次确认一条消息 时间是安全的

channel.basicAck(标记,false)
是线程安全的

但是
consumerChannel.basicAck(tag,true)
不是

还有一些在

资料来源中提到的优点:

使用手动确认时,重要的是考虑。 确认的线索是什么。如果它与 接收交付的线程(例如,消费者处理交付 将交付处理委托给不同的线程),通过 设置为true的多参数不安全,将导致 双重确认,因此是通道级协议 关闭通道的异常。一次确认一条消息 时间是安全的

channel.basicAck(标记,false)
是线程安全的

但是
consumerChannel.basicAck(tag,true)
不是


另外,您所参考的文档中提到的一些优点是针对Java客户机的。你应该指的是

您使用的是最新版本的.NET客户端(
5.1
),因此在
Received
事件处理程序中执行您的工作不会阻止处理TCP数据的其他线程,也不会阻止心跳-这两者都很好

首先,调用
channel.BasicQos(0,1,false)
意味着您的消费者一次只能从RabbitMQ收到一条就绪消息,并且在调用
BasicAck
之前,不会传递另一条消息。所以,实际上没有理由在另一个线程中进行工作,因为你无论如何都不会收到另一条消息

如果您增加预取值(通过实验和运行基准测试),那么如果您的工作运行时间超过几毫秒,您将不得不在后台线程中执行工作

当您在
Received
事件回调中执行工作时,它将阻止用于进行回调的线程,因为回调不会在自己的线程上执行。因此,您可以确保您的工作非常短,或者在另一个线程中完成工作

我刚刚花了一些时间检查.NET客户端代码,我非常确定
IModel
实例不是线程安全的。如果增加预回迁,您将有机会同时确认多条消息,因此我建议实施一个解决方案,使用该解决方案并确保在创建连接的同一线程上调用
BasicAck



注意:RabbitMQ团队监视
RabbitMQ用户,并且只在某些时候回答有关StackOverflow的问题。

您所参考的文档是针对Java客户端的。你应该指的是

您使用的是最新版本的.NET客户端(
5.1
),因此在
Received
事件处理程序中执行您的工作不会阻止处理TCP数据的其他线程,也不会阻止心跳-这两者都很好

首先,调用
channel.BasicQos(0,1,false)
意味着您的消费者一次只能从RabbitMQ收到一条就绪消息,并且在调用
BasicAck
之前,不会传递另一条消息。所以,实际上没有理由在另一个线程中进行工作,因为你无论如何都不会收到另一条消息

如果您增加预取值(通过实验和运行基准测试),那么如果您的工作运行时间超过几毫秒,您将不得不在后台线程中执行工作

当您在
Received
事件回调中执行工作时,它将阻止用于进行回调的线程,因为回调不会在自己的线程上执行。因此,您可以确保您的工作非常短,或者在另一个线程中完成工作

我刚刚花了一些时间检查.NET客户端代码,我非常确定
IModel
实例不是线程安全的。如果增加预回迁,您将有机会同时确认多条消息,因此我建议实施一个解决方案,使用该解决方案并确保在创建连接的同一线程上调用
BasicAck



注意:RabbitMQ团队监控
RabbitMQ用户
,并且有时只回答有关StackOverflow的问题。

就个人而言,我讨厌RabbitMQ API,哟