System.Threading.Tasks,在该命名空间下Task是主类,表示一个类的异步的并发的操作,创建并行代码的时候不一定要直接使用Task类,在某些情况下可以直接使用Parallel静态类(System.Threading.Tasks.Parallel)下所提供的方法进行并行开发,而不用底层的Task实例。
并行处理无法保证顺序,不需要考虑任务和线程的问题,执行效率加快,当然也不是绝对的,任务的开销大小对并行任务有影响,如果任务很小,那么由于并行管理的附加开销(任务分配,调度,同步等成本),可能并行执行并不是优化方案。例如:循环打印10000个数字,for的循环比Parallel.For快
Parallel 类的使用(System.Threading.Tasks)
提供对并行循环和区域的支持。在Parallel下面有三个常用的方法invoke,For和ForEach。
Stopwatch stopWatch = new Stopwatch(); List<int> sourceList = new List<int>(); for (int i = 0; i <= 10000; i++) { sourceList.Add(i); } stopWatch.Reset(); stopWatch.Start(); List<int> resultList = new List<int>(); foreach (int option in sourceList) { Thread.Sleep(1); resultList.Add(option); } stopWatch.Stop(); Console.WriteLine("正常运行:" + stopWatch.ElapsedMilliseconds + " ms."); stopWatch.Reset(); stopWatch.Start(); ConcurrentBag<int> concurrentBagList = new ConcurrentBag<int>(); ParallelOptions options = new ParallelOptions(); options.MaxDegreeOfParallelism = 4; Parallel.ForEach(sourceList, options, (item) => { Thread.Sleep(1); concurrentBagList.Add(item); }); stopWatch.Stop(); Console.WriteLine("并行运行:" + stopWatch.ElapsedMilliseconds + " ms.");
上面的例子,如果把Thread.Sleep(1),去掉可以发现,foreach比Parallel.ForEach快,所以任务的开销很重要。ConcurrentBag如果换成List可以发现,list中的数据不够。List集合,数组Int[],String[] ……,Dictory字典等等。但是这些列表、集合和数组的线程都不是安全的,不能接受并发请求。微软也提供了线程安全的类Concurrent
Concurrent类(System.Collections)
命名空间提供多个线程安全集合类。当有多个线程并发访问集合时,应使用这些类代替 System.Collections 和 System.Collections.Generic 命名空间中的对应类型。
BlockingCollection<T> 为实现 IProducerConsumerCollection<T> 的线程安全集合提供阻塞和限制功能。
ConcurrentBag<T> 表示对象的线程安全的无序集合。可以用来替换List<T>
ConcurrentDictionary<TKey, TValue> 表示可由多个线程同时访问的键值对的线程安全集合。Dictionary<TKey, TValue>
ConcurrentQueue<T> 表示线程安全的先进先出 (FIFO) 集合。Queue<T>
ConcurrentStack<T> 表示线程安全的后进先出 (LIFO) 集合。Stack<T>
NuGet中AsyncEnumerator
并行中的多线程
await list.ParallelForEachAsync(async l => { ....... });
其他的多线程文章
2. .NET中并行开发优化
3. C# Task.Run 和 Task.Factory.StartNew 区别
4. C#中多线程的并行处理
5. C#中多线程中变量研究