多线程处理任务,相同主键按顺序处理任务

直接上代码

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks.Dataflow;

namespace ConsoleApp1.Threading
{
    public class ThreadingTest
    {
        const int ThreadingCount = 100;
        int _total = 0;

        readonly Random _random;
        readonly Stopwatch _watch;

        /// <summary>
        /// 处理中的数据量
        /// </summary>
        readonly ConcurrentDictionary<long, HandlerDetail> _memberHandlerDetailDic;

        /// <summary>
        /// 输出方便显示用
        /// </summary>
        readonly ConcurrentDictionary<string, List<string>> _writeLineDic;

        /// <summary>
        /// 业务队列
        /// <para>item1业务ID item2自己处理的顺序 item3任务信息</para>
        /// </summary>
        ActionBlock<Tuple<long, int, string>> _actionBlock;

        public ThreadingTest()
        {
            _random = new Random();
            _watch = new Stopwatch();
            _memberHandlerDetailDic = new ConcurrentDictionary<long, HandlerDetail>();
            _writeLineDic = new ConcurrentDictionary<string, List<string>>();
            _actionBlock = new ActionBlock<Tuple<long, int, string>>(Handler, new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = ThreadingCount });
        }

        public void Main()
        {
            _watch.Start();

            var taskCount = 5000;
            for (int i = 0; i < taskCount; i++)
            {
                Consume(new Tuple<long, string>(_random.Next(1, ThreadingCount + 10), $"Task序号{i:000000}"));
            }

            var totalTime = _watch.Elapsed.TotalMilliseconds;

            Console.WriteLine($"============入队完成");

            // 等待完成
            SpinWait.SpinUntil(() => _total >= taskCount);

            // 打印
            foreach (var dic in _writeLineDic)
            {
                foreach (var item in dic.Value)
                {
                    Console.WriteLine($"{dic.Key}{item}");
                }
                Console.WriteLine();
            }

            var totalHandleTime = _watch.Elapsed.TotalMilliseconds;

            Console.WriteLine($"============处理时间统计:{totalHandleTime}ms");
            Console.WriteLine($"============入队时间统计:{totalTime}ms");
            Console.WriteLine($"============处理完成数量:{_total}");

        }

        /// <summary>
        /// 消费
        /// </summary>
        private void Consume(Tuple<long, string> tuple)
        {
            var cur = ModifyHandlerDetail(tuple.Item1, 1);

            RemoveMemberHandlerDetailDic();

            // 入队解耦
            _actionBlock.Post(new Tuple<long, int, string>(tuple.Item1, cur, tuple.Item2));

        }

        /// <summary>
        /// 定时清理列表
        /// </summary>
        private void RemoveMemberHandlerDetailDic()
        {
            if (DateTime.Now.Minute % 30 == 1)
            {
                var removeList = new List<long>();
                foreach (var item in _memberHandlerDetailDic)
                {
                    if (item.Value.Outstanding == 0) removeList.Add(item.Key);
                }
                foreach (var key in removeList)
                {
                    _memberHandlerDetailDic.TryRemove(key, out _);
                }
            }
        }

        /// <summary>
        /// 业务处理
        /// </summary>
        /// <param name="tuple"></param>
        private void Handler(Tuple<long, int, string> tuple)
        {
            var startTime = $"{DateTime.Now:HH:mm:ss fff}";

            var startWait = _watch.Elapsed.TotalMilliseconds;

            // 等待
            SpinWait.SpinUntil(() => tuple.Item2 - _memberHandlerDetailDic[tuple.Item1].Completions == 1);

            var endWait = _watch.Elapsed.TotalMilliseconds;

            try
            {
                // 随机处理时间
                Thread.Sleep(_random.Next(50, 600));

                var item1 = $"ID:{tuple.Item1:0000000000}";
                var item3 = $" 处理任务:{tuple.Item3} 开始时间:{startTime} 完成时间:{DateTime.Now:HH:mm:ss fff} 等待时间:{endWait - startWait}";

                _writeLineDic.AddOrUpdate(item1, new List<string>() { item3 }, (key, value) =>
                {
                    value.Add(item3);
                    return value;
                });

                Console.WriteLine($"{item3}");

            }
            catch (Exception ex)
            {

                throw;
            }

            // 统计处理数量
            Interlocked.Increment(ref _total);

            ModifyHandlerDetail(tuple.Item1, -1);

        }

        /// <summary>
        /// 修改处理中的任务量
        /// </summary>
        /// <param name="key"></param>
        /// <param name="count"></param>
        private int ModifyHandlerDetail(long key, int count)
        {
            var selfCurrent = 1;

            _memberHandlerDetailDic.AddOrUpdate(key, new HandlerDetail { Outstanding = 1, Current = 1, Completions = 0 }, (k, value) =>
            {
                value.Outstanding += count;
                if (count < 0)
                {
                    value.Completions += -count;
                }
                else
                {
                    value.Current += count;
                    selfCurrent = value.Current;
                }

                return value;
            });

            return selfCurrent;
        }

    }

    public class HandlerDetail
    {
        /// <summary>
        /// 未完成数
        /// </summary>
        public int Outstanding { get; set; }

        /// <summary>
        /// 当前第N个
        /// </summary>
        public int Current { get; set; }

        /// <summary>
        /// 已完成数
        /// </summary>
        public int Completions { get; set; }
    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值