C# 多线程与队列
使用多线程的时候,如果线程执行的函数需要记录返回结果,那么要保证存储结果的对象安全可靠。
ConcurrentQueue 高效的线程安全队列,能够在使用多线程的时候保障程序安全可靠
一:参数很多,需要多次调用同一函数并汇总返回结果
//参数很多,单方法,需要反复多次调用
public static void TaskMoreParam()
{
var paramlist = new List<int>();//大量的参数
for (var i = 0; i < 100; i++)
{
paramlist.Add(i);
}
// 将参数放到队列,然后开启线程,线程里面队列来调用方法。
List<Task> tasks = new List<Task>();
//入参
var Queue = new ConcurrentQueue<int>();
//结果集
var rQueue = new ConcurrentQueue<int>();
//将参数放到队列中
for (int i = 0; i < paramlist.Count; i++)
{
Queue.Enqueue(i);
}
#region 使用task
for (int i = 0; i < 10; i++)
{
//创建多线程
var task = Task.Run(() =>
{
//如果参数队列里面还有数据则继续执行
while (Queue.Count > 0)
{
//从参数队列里面取出参数,同时将参数从队列中移除
Queue.TryDequeue(out int a);
//调用具体函数,将返回结果存放在队列中
rQueue.Enqueue(GetNumber(a));
}
});
tasks.Add(task);
}
//等线程全部执行完毕。
Task.WhenAll(tasks.ToArray());
#endregion
#region 使用 Parallel
//Queue 将队列作为参数,比集合的好处在于取数据避免并发
//假如 函数执行很慢,多线程在跑的时候可能会并发,两个线程拿到同一个参数导致有参数丢失
ParallelLoopResult res = Parallel.ForEach(Queue, new ParallelOptions() { MaxDegreeOfParallelism = 10 }, (i) =>
{
rQueue.Enqueue(GetNumber(i));
});
#endregion
var resultlist = rQueue.ToList();
}
执行函数
//待执行函数
public static int GetNumber(int i)
{
Thread.Sleep(1000);
return i * 2;
}
二:同一参数,多函数调用,而且函数耗时,需要统计返回结果
//多方法。很耗时
public static void TaskSlow()
{
int param = 1;
// 将参数放到队列,然后开启线程,线程里面队列来调用方法。
List<Task> tasks = new List<Task>();
//入参
var Queue = new ConcurrentQueue<Func<int, int>>();
//结果集
var rQueue = new ConcurrentQueue<int>();
//将方法放入队列
Queue.Enqueue(GetNumber);
Queue.Enqueue(GetNumber1);
Queue.Enqueue(GetNumber2);
#region 使用 Parallel
//Queue 将队列作为参数,比集合的好处在于取数据避免并发
//假如 函数执行很慢,多线程在跑的时候可能会并发,两个线程拿到同一个参数导致有参数丢失
ParallelLoopResult res = Parallel.ForEach(Queue, new ParallelOptions() { MaxDegreeOfParallelism = 10 }, (fun) => rQueue.Enqueue(fun(param)));
#endregion
var resultlist = rQueue.ToList();
}
//待执行函数
public static int GetNumber(int i)
{
Thread.Sleep(1000);
return i * 2;
}
public static int GetNumber1(int i)
{
Thread.Sleep(1000);
return i * 2;
}
public static int GetNumber2(int i)
{
Thread.Sleep(1000);
return i * 2;
}
三:记录一次踩坑
将多线程的结果存放在List结果中,这里会有问题,List是一种线性表,内部可以是以一种数组来存储的,那么在多线程情况下,可能多条结果同时赋值给了一个数组,最后结果覆盖,于是返回结果丢失
//参数很多,需要反复多次调用
public static void TaskMoreParam1()
{
var paramlist = new List<int>();//大量的参数
for (var i = 0; i < 100; i++)
{
paramlist.Add(i);
}
// 将参数放到队列,然后开启线程,线程里面队列来调用方法。
List<Task> tasks = new List<Task>();
//入参
var Queue = new ConcurrentQueue<int>();
//结果集
var rQueue = new List<int>();
//将参数放到队列中
for (int i = 0; i < paramlist.Count; i++)
{
Queue.Enqueue(i);
}
#region 使用 Parallel
//Queue 将队列作为参数,比集合的好处在于取数据避免并发
//假如 函数执行很慢,多线程在跑的时候可能会并发,两个线程拿到同一个参数导致有参数丢失
ParallelLoopResult res = Parallel.ForEach(Queue, new ParallelOptions() { MaxDegreeOfParallelism = 10 }, (i) =>
{
Console.WriteLine(i);
rQueue.Add(GetNumber(i));//此处有问题
});
#endregion
var resultlist = rQueue.ToList();
var str = string.Join(",", resultlist);
}

浙公网安备 33010602011771号