C # queue study notes: RabbitMQ uses multithreading to increase consumption throughput

    I. Introduction

    One benefit of using a work queue is that it can process queues in parallel. If there are many tasks stacked, we only need to add more workers (workers), the expansion is very simple. This example uses multiple threads to create multiple channels and bind queues to achieve the goal of multiple workers.

    Second, the example

    2.1, environmental preparation

    Install RabbitMQ.Client on NuGet.

    2.2 Factory

    Add a factory class RabbitMQFactory:

    ///  <summary> 
    /// Multiplexing technology (Multiplexing) Purpose: To avoid wasting and overloading of system resources caused by creating multiple TCPs, thereby effectively using TCP connections.
    ///  </ summary> 
    public  static  class RabbitMQFactory 
    { 
        private  static IConnection sharedConnection;
         private  static  int ChannelCount { get ; set ;}
         private  static  readonly  object _locker = new  object (); 

        public  static IConnection SharedConnection 
        { 
            get 
            { 
                if (ChannelCount >= 1000)
                {
                    if (sharedConnection != null && sharedConnection.IsOpen)
                    {
                        sharedConnection.Close();
                    }
                    sharedConnection = null;
                    ChannelCount = 0;
                }
                if (sharedConnection == null)
                {
                    lock (_locker)
                    {
                        if (sharedConnection == null)
                        {
                            sharedConnection = GetConnection();
                            ChannelCount++;
                        }
                    }
                }
                return sharedConnection;
            }
        }

        private static IConnection GetConnection()
        {
            var factory = new ConnectionFactory
            {
                HostName = "192.168.2.242",
                UserName = "hello",
                Password = "world",
                Port = AmqpTcpEndpoint.UseDefaultPort,//5672
                VirtualHost = ConnectionFactory.DefaultVHost,//使用默认值:"/"
                Protocol = Protocols.DefaultProtocol,
                AutomaticRecoveryEnabled = true
            };
            return factory.CreateConnection();
        }
    }
View Code

    2.3, the main form

    code show as below:

    public partial class RabbitMQMultithreading : Form
    {
        public delegate void ListViewDelegate<T>(T obj);

        public RabbitMQMultithreading()
        {
            InitializeComponent();
        }

        /// <summary>
        /// ShowMessage重载
        /// </summary>
        /// <param name="msg"></param>
        private void ShowMessage(string msg)
        {
            if (InvokeRequired)
            {
                BeginInvoke(new ListViewDelegate<string>(ShowMessage), msg);
            }
            else
            {
                ListViewItem item = new ListViewItem(new string[] { DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss ffffff"), msg });
                lvwMsg.Items.Insert(0, item);
            }
        }

        /// <summary>
        /// ShowMessage重载
        /// </summary>
        /// <param name="format"></param>
        /// <param name="args"></param>
        private void ShowMessage(string format, params object[] args)
        {
            if (InvokeRequired)
            {
                BeginInvoke(new MethodInvoker(delegate ()
                {
                    ListViewItem item = new ListViewItem(new string[] { DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss ffffff"), string.Format(format, args) });
                    lvwMsg.Items.Insert(0, item);
                }));
            }
            else
            {
                ListViewItem item = new ListViewItem(new string[] { DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss ffffff"), string.Format(format, args) });
                lvwMsg.Items.Insert(0, item);
            }
        }

        /// <summary>
        /// 生产者
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSend_Click(object sender, EventArgs e)
        {
            int messageCount = 100;
            var factory = new ConnectionFactory
            {
                HostName = "192.168.2.242",
                UserName = "hello",
                Password = "world",
                Port = AmqpTcpEndpoint.UseDefaultPort,//5672
                VirtualHost = ConnectionFactory.DefaultVHost,//使用默认值:"/"
                Protocol = Protocols.DefaultProtocol,
                AutomaticRecoveryEnabled = true
            };
            using (var connection = factory.CreateConnection())
            {
                using (var channel = connection.CreateModel())
                {
                    channel.QueueDeclare(queue: "hello", durable: true, exclusive: false, autoDelete: false, arguments: null);
                    string message = "Hello World";
                    var body = Encoding.UTF8.GetBytes(message);
                    for (int i = 1; i <= messageCount; i++)
                    {
                        channel.BasicPublish(exchange: "", routingKey: "hello", basicProperties: null, body: body);
                        ShowMessage($"Send {message}");
                    }
                }
            }
        }

        /// <summary>
        /// 消费者
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void btnReceive_Click(object sender, EventArgs e)
        {
            Random random = new Random();
            int rallyNumber = random.Next(1, 1000);
            int channelCount = 0;

            await Task.Run(() =>
            {
                try
                {
                    int asyncCount = 10;
                    List<Task<bool>> tasks = new List<Task<bool>>();
                    var connection = RabbitMQFactory.SharedConnection;
                    for (int i = 1; i <= asyncCount; i++)
                    {
                        tasks.Add(Task.Factory.StartNew(() => MessageWorkItemCallback(connection, rallyNumber)));
                    }
                    Task.WaitAll(tasks.ToArray());

                    string syncResultMsg = $"集结号 {rallyNumber} 已吹起号角--" +
                        $"Number of successful channel openings this time: {tasks.Count (s => s.Result == true)}, " + 
                        $ " Number of channel opening failures this time: {tasks.Count ()-tasks.Count (s => s .Result == true)} " + 
                        $ " The cumulative number of successful channel openings: {channelCount + tasks.Count (s => s.Result == true)} " ; 
                    ShowMessage (syncResultMsg); 
                } 
                catch (Exception ex) 
                { 
                    ShowMessage ($ " Assembly number {rallyNumber} consumption exception: {ex.Message} " ); 
                } 
            }); 
        } 

        ///  <summary> 
        /// 异步方法
        /// </summary>
        /// <param name="state"></param>
        /// <param name="rallyNumber"></param>
        /// <returns></returns>
        private bool MessageWorkItemCallback(object state, int rallyNumber)
        {
            bool syncResult = false;
            IModel channel = null;
            try
            {
                IConnection connection = state as IConnection;
                //You cannot use using (channel = connection.CreateModel ()) to create a channel and let RabbitMQ automatically recycle the channel. 
                channel = connection.CreateModel (); 
                channel.QueueDeclare (queue: " hello " , durable: true , exclusive: false , autoDelete: false , arguments: null ); 
                channel.BasicQos (prefetchSize: 0 , prefetchCount: 1 , global : false );
                 var consumer = new EventingBasicConsumer (channel); 
                consumer.Received + = (model, ea) =>
                {
                    var message = Encoding.UTF8.GetString(ea.Body);
                    Thread.Sleep(1000);
                    ShowMessage($"集结号 {rallyNumber} Received {message}");
                    channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false);
                };
                channel.BasicConsume(queue: "hello", autoAck: false, consumer: consumer);
                syncResult = true;
            }
            catch (Exception ex)
            {
                syncResult = false;
                ShowMessage(ex.Message);
            }
            return syncResult;
        }
    }
View Code

    2.4. Operation result

    Consumers can increase the number of channels a few times and increase their spending power.

Guess you like

Origin www.cnblogs.com/atomy/p/12680782.html