首页 > Python基础教程 >
-
C#教程之并行编程(Parallel Framework)(2)
结果如下:
For的版本如下:
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 string[] data = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" }; 6 Parallel.For(0, data.Length, (i, state) => 7 { 8 Console.WriteLine($"当前索引为:{i},状态为:{state}"); 9 Test(data[i]); 10 if (data[i] == "six") 11 state.Break(); 12 }); 13 Console.ReadKey(); 14 } 15 static void Test(string str) 16 { 17 Console.WriteLine($"当前线程Id:{Thread.CurrentThread.ManagedThreadId},输出结果为:{str}"); 18 } 19 }
任务并行
对于任务并行的内容,请戳 任务(Task) 和 异步编程(async&await)。
并发集合概述
.NET 4.0在System.Collections.Concurrent命名空间中提供了一组新的集合。所有这些集合都完全是线程安全的:
这些集合不仅是为使用带锁的普通集合提供了快捷方式,而且可以在一般的多线程中使用并发集合,但需要注意:
1.并发集合针对并行编程进行了调整。只有在高度并发的应用场景中,传统集合的性能才能胜过它们。
2.线程安全的集合不能确保使用它的代码也是安全的。
3.如果枚举一个并发集合的同时,另一个线程要修改它,不会抛出任何异常,相反,得到旧内容与新内容的混合。
4.不存在任何List<T>的并发版本。
5.它们的内存利用率没有非并发的Stack和Queue类高效,但对于并发访问的效果更好。
1.结构概述
这些并发集合与传统集合的区别是:它们公开了特殊方法来执行原子测试和行动操作,而这些方法都是通过IProducerConsumerCollection<T>接口提供的。
IProducerConsumerCollection<T>接口代表一个线程安全的生产者/消费者集合,这三个类继承并实现了IProducerConsumerCollection<T>接口:
ConcurrentStack<T>、ConcurrentQueue<T>、ConcurrentBag<T>。
它们实现的TryAdd和TryTake方法用于测试一个添加/删除操作能否执行,如果可以,则执行添加/删除操作。测试与行动不需要对传统集合上锁。
ConcurrentBag<T>用于保存对象的无需集合,适用于调用Take或TryTake时不关心获取那个元素的额情况。
相对于并发队列或堆栈,在多线程同时调用一个ConcurrentBag的Add时,不存在竞争,但队列或堆栈并行调用Add会引起一些竞争,所以ConcurrentBag上调用Take方法非常高效。
BlockingCollection<T>类似阻塞集合,适用于等待新元素的出现,可以把它看作一个容器,使用一个阻塞集合封装所有实现IProducerConsumerCollection<T>的集合,并且允许从封装的集合中去除元素,若没有元素,操作会阻塞
2.基础方法
常用的一些方法,整理自 zy__ :
ConcurrentQueue:完全无锁,但面临资源竞争失败时可能会陷入自旋并重试操作。
Enqueue:在队尾插入元素
TryDequeue:尝试删除队头元素,并通过out参数返回
TryPeek:尝试将对头元素通过out参数返回,但不删除该元素。
ConcurrentStack:完全无锁,但面临资源竞争失败时可能会陷入自旋并重试操作。
Push:向栈顶插入元素
TryPop:从栈顶弹出元素,并且通过out 参数返回
TryPeek:返回栈顶元素,但不弹出。
ConcurrentBag:一个无序的集合,程序可以向其中插入元素,或删除元素。在同一个线程中向集合插入,删除元素的效率很高。
Add:向集合中插入元素
TryTake:从集合中取出元素并删除
TryPeek:从集合中取出元素,但不删除该元素。
BlockingCollection:一个支持界限和阻塞的容器
Add :向容器中插入元素
TryTake:从容器中取出元素并删除
TryPeek:从容器中取出元素,但不删除。
CompleteAdding:告诉容器,添加元素完成。此时如果还想继续添加会发生异常。
IsCompleted:告诉消费线程,生产者线程还在继续运行中,任务还未完成。
ConcurrentDictionary:对于读操作是完全无锁的,当很多线程要修改数据时,它会使用细粒度的锁。
AddOrUpdate:如果键不存在,方法会在容器中添加新的键和值,如果存在,则更新现有的键和值。
GetOrAdd:如果键不存在,方法会向容器中添加新的键和值,如果存在则返回现有的值,并不添加新值。
TryAdd:尝试在容器中添加新的键和值。TryGetValue:尝试根据指定的键获得值。
TryRemove:尝试删除指定的键。
TryUpdate:有条件的更新当前键所对应的值。
GetEnumerator:返回一个能够遍历整个容器的枚举器。
结语
根据ConcurrentBag编写线程安全的生产者消费者请戳:这里 。
说实在的写这篇文章挺烦的,主要涉及的知识点太多讲的太细篇幅会很长况且我自己有些也还没用过,所以是概述性文章,对PFX有个基本的认识,当需要具体深入使用某些知识时再查询相关文档。
关于 并发编程(Concurrent programming)更新到这里基本已经完结,谢谢大家的支持。
因个人的兴趣,所以准备沉淀下来专攻 数据结构和算法,然后研究 人工智能(Microsoft的人工智能平台Windows ML不会涉及,选择研究Google的第二代人工智能学习系统TensorFlow )。
接下来会对Linux、Python进行基础的学习并更新文章。
但是最核心的还是数据结构&算法使用那种编程语言并不重要,。
感兴趣的朋友可以关注。