灰灰狼

灰灰的狼

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

增加了并发数量的支持,做了些完美主义化:

    public abstract class MessageQueueConcurrentHandlerBase<T> : IMessageQueueHandler
    {
        public MessageQueueConcurrentHandlerBase(string queueName, int maxConcurrency = 5, Action<string> logDelegate = null)
        {
            if (!MessageQueue.Exists(queueName))
                throw new Exception(string.Format("No such a queue: {0}", queueName));
            if (maxConcurrency < 1)
                throw new ArgumentOutOfRangeException("maxConcurrency");

            this._queueName = queueName;
            this._poolForConsumer = new Semaphore(0, maxConcurrency);
            this._producerAutoResetEvent = new AutoResetEvent(false);
            this._maxConcurrency = maxConcurrency;
            this._logDelegate = logDelegate;
        }

        public void StartRead()
        {
            this._queue = new MessageQueue(this._queueName) { Formatter = new XmlMessageFormatter(new Type[] { typeof(long) }) };
            this._queue.PeekCompleted += new PeekCompletedEventHandler(Produce);
            this._producerAutoResetEvent.Set();
            this._poolForConsumer.Release(this._maxConcurrency);

            this._queue.BeginPeek();
        }

        public override string ToString()
        {
            return string.Format("{0}-{1}", this.HandlerName, this._queueName);
        }

        public long CurrentWorkerCount { get { return Interlocked.Read(ref this._currentWorkerCount); } }

        public int MaxConcurrency { get { return _maxConcurrency; } }

        protected abstract string HandlerName { get; }

        protected abstract void MainProcess(T messageItem, string consumerName);

        protected void LogInfo(string msg)
        {
            if (_logDelegate != null)
            {
                this._logDelegate(msg);
            }
        }

        #region private
        private void Produce(object sender, PeekCompletedEventArgs e)
        {
            this._producerAutoResetEvent.WaitOne();

            var message = this._queue.EndPeek(e.AsyncResult);

            long consumerIndex = Interlocked.Increment(ref this._consumerIndex);
            ThreadPool.QueueUserWorkItem(new WaitCallback(this.Consume), consumerIndex);
            this._queue.BeginPeek();
        }

        private void Consume(object stateInfo)
        {
            long consumerIndex = (long)stateInfo;
            string consumerName = string.Format("{0}-{1}", this.HandlerName, consumerIndex);

            this._poolForConsumer.WaitOne();

            var message = this._queue.Receive();
            this._producerAutoResetEvent.Set();

            T messageItem = (T)message.Body;

            this.LogInfo(string.Format("{0} Received a message, MessageItem = {1}", consumerName, messageItem));
            Interlocked.Increment(ref this._currentWorkerCount);

            try
            {
                this.LogInfo(string.Format("{0} will run MainProcess, MessageItem = {1}, CurrentWorkerCount = {2}", consumerName, messageItem, this.CurrentWorkerCount));
                MainProcess(messageItem, consumerName);
            }
            catch (Exception ex)
            {
                this.HandleException(ex, messageItem);
            }
            finally
            {
                Interlocked.Decrement(ref this._currentWorkerCount);

                this.LogInfo(string.Format("{0} run over, messageItem = {1}, CurrentWorkerCount = {2}", consumerName, messageItem, this.CurrentWorkerCount));
            }

            this._poolForConsumer.Release();
        }

        private void HandleException(Exception ex, T messageItem)
        {
            this.LogInfo(string.Format("Exception in {0}:[Message]={1},[StackTrace]={2},[Type]={3},[CurrentWorkerCount]={4},[messageItem]={5}", this.HandlerName, ex.GetBaseException().Message, ex.StackTrace, ex.GetType(), this.CurrentWorkerCount, messageItem));
        }

        private readonly string _queueName;
        private MessageQueue _queue;
        private long _currentWorkerCount;
        private Semaphore _poolForConsumer;
        private AutoResetEvent _producerAutoResetEvent;
        private int _maxConcurrency;
        private Action<string> _logDelegate;
        private long _consumerIndex = 0;
        #endregion
    }

 

以下是测试代码,觉得好就表扬一下啊:)

    class Program : MessageQueueConcurrentHandlerBase<long>
    {
        public Program(string queueName, int maxConcurrency, Action<string> logDelegate)
            : base(queueName, maxConcurrency, logDelegate)
        {

        }

        protected override void MainProcess(long messageItem, string consumerName)
        {
            Thread.Sleep(5 * 1000);
            this.LogInfo(string.Format("{0}-MainProcess Over:\tmessageItem = {1}, CurrentWorkerCount = {2}", consumerName, messageItem, this.CurrentWorkerCount));
        }

        protected override string HandlerName { get { return "TestQueueHandler"; } }

        static void Main(string[] args)
        {
            string queuePath = CreateQueueIfNotExist("MyQueue");
            MessageQueue myQueue = new MessageQueue(queuePath);

            IMessageQueueHandler messageQueueHandler = new Program(queuePath, 3, s => { Console.WriteLine(s); });
            messageQueueHandler.StartRead();
            long x = 0;
            do
            {
                foreach (var s in Console.ReadLine().Split(",".ToCharArray()))
                {
                    if (long.TryParse(s.Trim(), out x))
                        myQueue.Send(x);
                }
            } while (x > 0);

            Console.ReadLine();
        }

        private static string CreateQueueIfNotExist(string queueName)
        {
            string queuePath = string.Format(@".\Private$\{0}", queueName);
            if (!MessageQueue.Exists(queuePath))
                MessageQueue.Create(queuePath);

            return queuePath;
        }
    }

 

posted on 2014-09-15 05:22  灰灰狼  阅读(509)  评论(1编辑  收藏  举报