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; }
}
测试结果
从测试结果来看,多线程节省了发送时间 但具体执行post请求会节省多少,还要看数据量,server配置,网络条件,等等相关因素的影响。
线程锁
这里笔者多说一点,代码开头有定义线程锁,但是时间匆忙没来得及加,为了保障线程安全还是要加的。
PS: 中午休息时间暂时写到这把,刚好要到上班时间了,欢迎多提宝贵意见,大家共同探讨。