C# 并行编程 之 并发集合 (.Net Framework 4.0)(转)
2015-12-11 11:12
411 查看
转载地址:http://blog.csdn.net/wangzhiyu1980/article/details/45497907
此文为个人学习《C#并行编程高级教程》的笔记,总结并调试了一些文章中的代码示例。 在以后开发过程中可以加以运用。
对于并行任务,与其相关紧密的就是对一些共享资源,数据结构的并行访问。经常要做的就是对一些队列进行加锁-解锁,然后执行类似插入,删除等等互斥操作。 .NetFramework 4.0 中提供了一些封装好的支持并行操作数据容器,可以减少并行编程的复杂程度。
并行容器:
ConcurrentQueue
ConcurrentStack
ConcurrentBag : 一个无序的数据结构集,当不需要考虑顺序时非常有用。
BlockingCollection : 与经典的阻塞队列数据结构类似
ConcurrentDictionary
这些集合在某种程度上使用了无锁技术(CAS Compare-and-Swap和内存屏障 Memory Barrier),与加互斥锁相比获得了性能的提升。但在串行程序中,最好不用这些集合,它们必然会影响性能。
关于CAS:
http://www.tuicool.com/articles/zuui6z http://www.360doc.com/content/11/0914/16/7656248_148221200.shtml
关于内存屏障
http://en.wikipedia.org/wiki/Memory_barrier
Enqueue:在队尾插入元素
TryDequeue:尝试删除队头元素,并通过out参数返回
TryPeek:尝试将对头元素通过out参数返回,但不删除该元素。
程序示例:
Push:向栈顶插入元素
TryPop:从栈顶弹出元素,并且通过out 参数返回
TryPeek:返回栈顶元素,但不弹出。
测试中一个有趣的现象:
虽然生产者已经在栈中插入值已经到了25,但消费者第一个出栈的居然是4,而不是25。很像是出错了。但仔细想想入栈,出栈和打印语句是两个部分,而且并不是原子操作,出现这种现象应该也算正常。
在同一个线程中向集合插入,删除元素的效率很高。
Add:向集合中插入元素
TryTake:从集合中取出元素并删除
TryPeek:从集合中取出元素,但不删除该元素。
程序示例:
Add :向容器中插入元素
TryTake:从容器中取出元素并删除
TryPeek:从容器中取出元素,但不删除。
CompleteAdding:告诉容器,添加元素完成。此时如果还想继续添加会发生异常。
IsCompleted:告诉消费线程,生产者线程还在继续运行中,任务还未完成。
示例程序:
程序中,消费者线程完全使用 while (!_TestBCollection.IsCompleted) 作为退出运行的判断条件。
在Worker1中,有两条语句被注释掉了,当i 为50时设置CompleteAdding,但当继续向其中插入元素时,系统抛出异常,提示无法再继续插入。
当然可以尝试在Work1中注释掉 CompleteAdding 语句,此时Work2陷入循环无法退出。
AddOrUpdate:如果键不存在,方法会在容器中添加新的键和值,如果存在,则更新现有的键和值。
GetOrAdd:如果键不存在,方法会向容器中添加新的键和值,如果存在则返回现有的值,并不添加新值。
TryAdd:尝试在容器中添加新的键和值。
TryGetValue:尝试根据指定的键获得值。
TryRemove:尝试删除指定的键。
TryUpdate:有条件的更新当前键所对应的值。
GetEnumerator:返回一个能够遍历整个容器的枚举器。
此文为个人学习《C#并行编程高级教程》的笔记,总结并调试了一些文章中的代码示例。 在以后开发过程中可以加以运用。
对于并行任务,与其相关紧密的就是对一些共享资源,数据结构的并行访问。经常要做的就是对一些队列进行加锁-解锁,然后执行类似插入,删除等等互斥操作。 .NetFramework 4.0 中提供了一些封装好的支持并行操作数据容器,可以减少并行编程的复杂程度。
基本信息
.NetFramework中并行集合的名字空间: System.Collections.Concurrent并行容器:
ConcurrentQueue
ConcurrentStack
ConcurrentBag : 一个无序的数据结构集,当不需要考虑顺序时非常有用。
BlockingCollection : 与经典的阻塞队列数据结构类似
ConcurrentDictionary
这些集合在某种程度上使用了无锁技术(CAS Compare-and-Swap和内存屏障 Memory Barrier),与加互斥锁相比获得了性能的提升。但在串行程序中,最好不用这些集合,它们必然会影响性能。
关于CAS:
http://www.tuicool.com/articles/zuui6z http://www.360doc.com/content/11/0914/16/7656248_148221200.shtml
关于内存屏障
http://en.wikipedia.org/wiki/Memory_barrier
用法与示例
ConcurrentQueue
其完全无锁,但当CAS面临资源竞争失败时可能会陷入自旋并重试操作。Enqueue:在队尾插入元素
TryDequeue:尝试删除队头元素,并通过out参数返回
TryPeek:尝试将对头元素通过out参数返回,但不删除该元素。
程序示例:
ConcurrentStack
其完全无锁,但当CAS面临资源竞争失败时可能会陷入自旋并重试操作。Push:向栈顶插入元素
TryPop:从栈顶弹出元素,并且通过out 参数返回
TryPeek:返回栈顶元素,但不弹出。
测试中一个有趣的现象:
虽然生产者已经在栈中插入值已经到了25,但消费者第一个出栈的居然是4,而不是25。很像是出错了。但仔细想想入栈,出栈和打印语句是两个部分,而且并不是原子操作,出现这种现象应该也算正常。
ConcurrentBag
一个无序的集合,程序可以向其中插入元素,或删除元素。在同一个线程中向集合插入,删除元素的效率很高。
Add:向集合中插入元素
TryTake:从集合中取出元素并删除
TryPeek:从集合中取出元素,但不删除该元素。
程序示例:
BlockingCollection
一个支持界限和阻塞的容器Add :向容器中插入元素
TryTake:从容器中取出元素并删除
TryPeek:从容器中取出元素,但不删除。
CompleteAdding:告诉容器,添加元素完成。此时如果还想继续添加会发生异常。
IsCompleted:告诉消费线程,生产者线程还在继续运行中,任务还未完成。
示例程序:
程序中,消费者线程完全使用 while (!_TestBCollection.IsCompleted) 作为退出运行的判断条件。
在Worker1中,有两条语句被注释掉了,当i 为50时设置CompleteAdding,但当继续向其中插入元素时,系统抛出异常,提示无法再继续插入。
当然可以尝试在Work1中注释掉 CompleteAdding 语句,此时Work2陷入循环无法退出。
ConcurrentDictionary
对于读操作是完全无锁的,当很多线程要修改数据时,它会使用细粒度的锁。AddOrUpdate:如果键不存在,方法会在容器中添加新的键和值,如果存在,则更新现有的键和值。
GetOrAdd:如果键不存在,方法会向容器中添加新的键和值,如果存在则返回现有的值,并不添加新值。
TryAdd:尝试在容器中添加新的键和值。
TryGetValue:尝试根据指定的键获得值。
TryRemove:尝试删除指定的键。
TryUpdate:有条件的更新当前键所对应的值。
GetEnumerator:返回一个能够遍历整个容器的枚举器。
相关文章推荐
- C#中WriteLine与Write的区别
- C#将图片转换层RGB32的byte
- c# timer使用
- c#初学-多线程中lock用法的经典实例
- C#如何在DataGridViewCell中自定义脚本编辑器
- pp看书笔记---C#高级编程第九版 第五章 【泛型】
- 精准定位c#.net程序高cpu的故障点
- CLR via C#学习笔记---类型
- C# Socket与实现
- C#获取当前应用程序所在路径及环境变量
- C#相关问题
- 计算两个DateTime间的时间差(小时差、�586钟差、秒钟差等)
- C#对DataGridView进行添加、修改、删除数据操作
- C#自定义属性
- Visual Studio自动添加头部注释 -C#开发2010-2013验证
- C#生成图片缩略图(2种思路)
- C#访问非托管内存
- C#当中的多线程_线程同步
- C#自定义DataGridViewColumn显示TreeView
- C#中的new和override