C# .NET多线程之Task的使用

C# .NET多线程之Task的使用

此文简单介绍下笔者的一点学习心得,希望对有需要的网友一些启发,不喜勿喷。

背景

公司最近公众号推送模板消息的需求频发,此公众号有60万以上用户,每次推送的人群由几千至十万以上不等,主要看目标用户群体划分,本来之前公众号很少量用户时,用for循环发送可以满足,但目前推送一个超过十万目标用户的需求需要耗费4h以上,期间不能推送任何其他模板消息,因此笔者想到了多线程。

需求

通过多线程的方式调用微信接口(微信模板消息接口不支持批量数据调用,只能每个目标用户调用一次),减少推送时间,以达到程序的优化。

Demo展示

// An Console Application.
class Program
    {
        static object lockObj = new object();
        // 最多同时开启5个线程,此处可根据电脑配置进行适当调整
        static int maxTask = 5;

        static void Main(string[] args)
        {
            List<Task> taskList = new List<Task>();
            List<User> users = new List<User>();
            // 模拟5W用户的场景
            for (int i = 0; i < 50000; i++)
            {
                User u = new User();
                u.openId = i.ToString();
                users.Add(u);
            }

            //var result = users.Select(int.Parse).GroupBy(i => i % 10).Select(g => g.ToList()).ToList();
            // 将User list转换成每10000个用为一组的list,分别分发给每个线程去发送post请求。
            List<List<User>> listGroup = new List<List<User>>();
            int j = 10000;
            for (int i = 0; i < users.Count; i += 10000)
            {
                List<User> cList = new List<User>();
                cList = users.Take(j).Skip(i).ToList();
                j += 10000;
                listGroup.Add(cList);
            }
			// for循环开始时间
            var forStartTime = DateTime.Now;
            for (int k = 0; k < users.Count; k++)
            {
                Console.WriteLine("for输出的id:" + users[k].openId + " 当前线程为" + Thread.CurrentThread.ManagedThreadId.ToString("00") + "号线程");
            }
			// for循环结束时间
            var forEndTime = DateTime.Now;
            var threadStartTime = forEndTime;

            listGroup.ForEach(userlist =>
            {
                var task = new Task(() =>
                {
                    Run(userlist);
                });
                task.Start();
                
                //Console.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString());
                if (taskList.Count > maxTask)
                {
                    Task.WaitAny(taskList.ToArray());
                    taskList = taskList.Where(t => t.Status == TaskStatus.Running).ToList();
                }
                taskList.Add(task);
            });
			// 等待所有线程都执行完,执行主线程操作。
            Task.WaitAll(taskList.ToArray());
            taskList = taskList.Where(t => t.Status == TaskStatus.Running).ToList();

            var forCostTime = forEndTime - forStartTime;
            var threadEndtime = DateTime.Now;
            var threadCostTime = threadEndtime - threadStartTime;

            Console.WriteLine("for cost time: " + forCostTime);
            Console.WriteLine("thread cost time: " + threadCostTime);

            Console.ReadLine();
        }

        public static void Run(List<User> users)
        {
            for (int i = 0; i < users.Count; i++)
            {
                Console.WriteLine("thread输出的id:" + users[i].openId + " 当前线程为" + Thread.CurrentThread.ManagedThreadId.ToString("00") + "号线程");
            }
                
        }

    }

    public class User
    {
        public string openId { get; set; }
    }

测试结果

多线程节省了4.01秒

从测试结果来看,多线程节省了发送时间 但具体执行post请求会节省多少,还要看数据量,server配置,网络条件,等等相关因素的影响。

线程锁

这里笔者多说一点,代码开头有定义线程锁,但是时间匆忙没来得及加,为了保障线程安全还是要加的。

PS: 中午休息时间暂时写到这把,刚好要到上班时间了,欢迎多提宝贵意见,大家共同探讨。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值