并行集合

对于并行任务,与其相关紧密的就是对一些共享资源,数据结构的并行访问.经常要做的就是对一些队列进行加锁-解锁,然后执行类似插入,删除等等互斥操作. .NET4提供了一些封装好的支持并行操作数据容器,可以减少并行编程的复杂程度.

并行集合的命名空间:System.Collections.Concurrent

并行容器:

ConcurrentQueue

ConcurrentStack

ConcurrentBag: 一个无序的数据结构集,当不考虑顺序时非常有用.

BlockingCollection:与经典的阻塞队列数据结构类似

ConcurrentDictoinary

以上这些集合在某种程度上使用了无锁技术(CAS和内存屏蔽),与加互斥锁相比获得了性能的提升.但是在串行程序中,最好不要使用这些集合,他们必然会影响性能.

ConcurrentQueue用法与实例

其完全无锁,但当CAS面临资源竞争失败时可能会陷入自旋并重试操作.

Enqueue:在队尾插入元素

TryDequeue:尝试删除对头元素,并通过out参数返回

TryPeek:尝试将对头元素通过out参数返回,但不删除元素

案例:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Collections.Concurrent;

namespace 并行结合Queue

{

class Program

{

internal static ConcurrentQueue<int> _TestQueue;

class ThreadWork1 //生产者

{

public ThreadWork1()

{ }

public void run()

{

Console.WriteLine("ThreadWork1 run { ");

for (int i = 0; i < 100; i++)

{

Console.WriteLine("ThreadWork1 producer: "+i);

_TestQueue.Enqueue(i);

}

Console.WriteLine("ThreadWork1 run } ");

}

}

class ThreadWork2 //consumer

{

public ThreadWork2()

{ }

public void run()

{

int i = 0;

bool IsDequeue = false;

Console.WriteLine("ThreadWork2 run { ");

for (; ; )

{

IsDequeue = _TestQueue.TryDequeue(out i);

if (IsDequeue)

{

System.Console.WriteLine("ThreadWork2 consumer: " + i * i + "   =====");

}

if (i==99)

{

break;

}

}

Console.WriteLine("ThreadWork2 run } ");

}

}

static void StartT1()

{

ThreadWork1 work1 = new ThreadWork1();

work1.run();

}

static void StartT2()

{

ThreadWork2 work2 = new ThreadWork2();

work2.run();

}

static void Main(string[] args)

{

Task t1 = new Task(() => StartT1());

Task t2 = new Task(() => StartT2());

_TestQueue = new ConcurrentQueue<int>();

Console.WriteLine("Sample 3-1 Main {");

Console.WriteLine("Main t1 t2 started {");

t1.Start();

t2.Start();

Console.WriteLine("Main t1 t2 started }");

Console.WriteLine("Main wait t1 t2 end {");

Task.WaitAll(t1, t2);

Console.WriteLine("Main wait t1 t2 end }");

Console.WriteLine("Sample 3-1 Main }");

Console.ReadKey();

}

}

}

ConcurrentStact

其完全无锁,但当CAS面临资源竞争失败时可能会陷入自旋并重试操作.

Push:向栈顶插入元素

TryPop:从栈顶弹出元素,并且通过out参数返回

TryPeek:返回栈顶元素,但不弹出

案例:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Collections.Concurrent;

namespace 并行结合Queue

{

class Program

{

internal static ConcurrentStack<int> _TestStack;

class ThreadWork1 //生产者

{

public ThreadWork1()

{ }

public void run()

{

Console.WriteLine("ThreadWork1 run { ");

for (int i = 0; i < 100; i++)

{

Console.WriteLine("ThreadWork1 producer: "+i);

_TestStack.Push(i);

}

Console.WriteLine("ThreadWork1 run } ");

}

}

class ThreadWork2 //consumer

{

public ThreadWork2()

{ }

public void run()

{

int i = 0;

bool IsDequeue = false;

Console.WriteLine("ThreadWork2 run { ");

for (; ; )

{

IsDequeue = _TestStack.TryPop(out i);

if (IsDequeue)

{

System.Console.WriteLine("ThreadWork2 consumer: " + i * i + "   =====" + i);

}

if (i==99)

{

break;

}

}

Console.WriteLine("ThreadWork2 run } ");

}

}

static void StartT1()

{

ThreadWork1 work1 = new ThreadWork1();

work1.run();

}

static void StartT2()

{

ThreadWork2 work2 = new ThreadWork2();

work2.run();

}

static void Main(string[] args)

{

Task t1 = new Task(() => StartT1());

Task t2 = new Task(() => StartT2());

_TestStack = new ConcurrentStack<int>();

Console.WriteLine("Sample 4-1 Main {");

Console.WriteLine("Main t1 t2 started {");

t1.Start();

t2.Start();

Console.WriteLine("Main t1 t2 started }");

Console.WriteLine("Main wait t1 t2 end {");

Task.WaitAll(t1, t2);

Console.WriteLine("Main wait t1 t2 end }");

Console.WriteLine("Sample 4-1 Main }");

Console.ReadKey();

}

}

}

ConcurrentBag

一个无序的集合,程序可以向其中插入元素,或删除元素.

在同一个线程中向集合插入,删除元素效率很高.

Add:向集合中插入元素

TryTake:从集合中取出元素并删除

TryPeek:从集合中取出元素,但不删除元素

案例:

using System;

using System.Collections.Concurrent;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

namespace 并行集合ConcurrentBag

{

class Program

{

internal static ConcurrentBag<int> _TestBag;

class ThreadWork1 //producer

{

public ThreadWork1()

{ }

public void run()

{

Console.WriteLine("Threadwork1 run { ");

for (int i = 0; i < 100; i++)

{

Console.WriteLine("ThreadWork1 producer: "+i);

_TestBag.Add(i);

}

Console.WriteLine("ThreadWork1 run } ");

}

}

class ThreadWork2//consumer

{

public ThreadWork2()

{ }

public void run()

{

bool IsDequeue = false;

Console.WriteLine("ThreadWork2 run { ");

for (int i = 0; i < 100; i++)

{

IsDequeue = _TestBag.TryTake(out i);

if (IsDequeue)

{

Console.WriteLine("ThreadWork2 consumer: " + i * i + "======" + i);

}

}

Console.WriteLine("ThreadWork2 run } ");

}

}

static void Start1()

{

ThreadWork1 work1 = new ThreadWork1();

work1.run();

}

static void Start2()

{

ThreadWork2 work2 = new ThreadWork2();

work2.run();

}

static void Main(string[] args)

{

Task t1 = new Task(() => Start1());

Task t2 = new Task(() => Start2());

_TestBag = new ConcurrentBag<int>();

t1.Start();

t2.Start();

Console.WriteLine("Main t1 t2 started }");

Console.WriteLine("Main wait t1 t2 end {");

Task.WaitAll(t1, t2);

Console.WriteLine("Main wait t1 t2 end }");

Console.WriteLine("Sample 4-3 Main }");

Console.ReadKey();

}

}

}

BlockingCollection

一个支持界限和阻塞的容器

Add:向容器中插入元素

TryTake:从容器中取出元素并删除

TryPeek:从容器中取出元素,但不删除

CompleteAdding:告诉容器,添加元素完成.此时如果还想继续添加会发生异常.

IsCompleted:告诉消费者线程,产生者线程还在继续运行中,任务还未完成.

案例:

程序中,消费者线程完全使用While(!__testCollection.IsCompleted)作为退出运行的判断条件.在Work1中,有两条语句被注释了,当i为50时设置为CompleteAdding,但当继续向其中插入元素时,系统抛出异常,提示无法再继续插入.

案例:

using System;

using System.Collections.Concurrent;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

namespace 并行结合Collection

{

class Program

{

internal static BlockingCollection<int> _testBCollection;

class ThreadWork1 //producer

{

public ThreadWork1()

{ }

public void run()

{

Console.WriteLine("ThreadWork1 run { ");

for (int i = 0; i < 100; i++)

{

Console.WriteLine("ThreadWork1 producer: "+i);

_testBCollection.Add(i);

//当i为50时设置为CompleteAdding,但当继续向其中插入元素时,系统抛出异常,提示无法再继续插入.

//if (i==50)

//{

//    _testBCollection.CompleteAdding();

//}

}

_testBCollection.CompleteAdding();

Console.WriteLine("ThreadWork1 run } ");

}

}

class ThreadWork2//consumer

{

public ThreadWork2()

{ }

public void run()

{

int i = 0;

bool IsDequeue = false;

Console.WriteLine("ThreadWork2 run { ");

while (!_testBCollection.IsCompleted)

{

//不明白这里为啥i会自动的++

//Console.WriteLine("i=================="+i);

IsDequeue = _testBCollection.TryTake(out i);

if (IsDequeue)

{

Console.WriteLine("ThreadWork2 consumer: "+i*i+"====="+i);

//i++;这句话不加还是会出现自动++的操作

}

}

}

}

static void StartT1()

{

ThreadWork1 work1 = new ThreadWork1();

work1.run();

}

static void StartT2()

{

ThreadWork2 work2 = new ThreadWork2();

work2.run();

}

static void Main(string[] args)

{

Task t1 = new Task(() => StartT1());

Task t2 = new Task(() => StartT2());

_testBCollection = new BlockingCollection<int>();

Console.WriteLine("Sample 4-4 Main {");

Console.WriteLine("Main t1 t2 started {");

t1.Start();

t2.Start();

Console.WriteLine("Main t1 t2 started }");

Console.WriteLine("Main wait t1 t2 end {");

Task.WaitAll(t1, t2);

Console.WriteLine("Main wait t1 t2 end }");

Console.WriteLine("Sample 4-4 Main }");

Console.ReadKey();

}

}

}

分析://_testBCollection.CompleteAdding();//这句话注释掉work2陷入循环,无法退出

ConcurrentDictionary

对于读操作是完全无锁的,当很多线程要修改数据时,它会使用细粒度的锁.

AddOrUpdate:如果键不存在,方法会在容器中添加新的键和值,如果存在,则更新现有的键和值

GetOrAdd:如果键不存在,方法会向容器中添加新的键和值,如果存在则返回现有的值,并不添加新值.

TryAdd:尝试在容器中添加新的键和值

TryGetValue:尝试根据指定的键获得值

TryUpdate:有条件的更新当前键所对应的值

TryRemove:尝试删除指定的键.

Getenumerator:返回一个能够遍历整个容器的枚举器.

案例:

using System;

using System.Collections.Concurrent;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

namespace 并行集合Dictionary

{

class Program

{

internal static ConcurrentDictionary<int, int> _TestDictionary;

class ThreadWork1//producer

{

public ThreadWork1()

{ }

public void run()

{

System.Console.WriteLine("ThreadWork1 run { ");

for (int i = 0; i < 100; i++)

{

System.Console.WriteLine("ThreadWork1 producer: " + i);

_TestDictionary.TryAdd(i, i);

}

System.Console.WriteLine("ThreadWork1 run } ");

}

}

class ThreadWork2//consumer

{

public ThreadWork2()

{ }

public void run()

{

bool IsOk = false;

Console.WriteLine("ThreadWork2 run { ");

int nCnt = 0,i=0,nValue=0;

while (nCnt<100)

{

IsOk = _TestDictionary.TryGetValue(i,out nValue);

if (IsOk)

{

Console.WriteLine("ThreadWork2 consumer: "+i*i+"====="+i);

nValue *= nValue;

nCnt++;

i++;

}

}

Console.WriteLine("ThreadWork2 run } ");

}

}

static void StartT1()

{

ThreadWork1 work1 = new ThreadWork1();

work1.run();

}

static void StartT2()

{

ThreadWork2 work2 = new ThreadWork2();

work2.run();

}

static void Main(string[] args)

{

Task t1 = new Task(() => StartT1());

Task t2 = new Task(() => StartT2());

bool bIsNext = true;

int nValue = 0;

_TestDictionary = new ConcurrentDictionary<int, int>();

Console.WriteLine("Sample 4-5 Main {");

Console.WriteLine("Main t1 t2 started {");

t1.Start();

t2.Start();

Console.WriteLine("Main t1 t2 started }");

Console.WriteLine("Main wait t1 t2 end {");

Task.WaitAll(t1, t2);

Console.WriteLine("Main wait t1 t2 end }");

foreach (var pair in _TestDictionary)

{

Console.WriteLine(pair.Key + " : " + pair.Value);

}

IEnumerator<KeyValuePair<int, int>> enumer = _TestDictionary.GetEnumerator();

while (bIsNext)

{

bIsNext = enumer.MoveNext();

Console.WriteLine("Key: " + enumer.Current.Key +"  Value: " + enumer.Current.Value);

_TestDictionary.TryRemove(enumer.Current.Key, out nValue);

}

Console.WriteLine("\n\nDictionary Count: " + _TestDictionary.Count);

Console.WriteLine("Sample 4-5 Main }");

Console.ReadKey();

}

}

}

总结说明: .NET4包含的新命名空间System.Collection,Concurrent有几个线程安全的集合类.线程安全的集合可防止多个线程以相互冲突的方式访问集合.

为了对集合进行线程安全的访问,定义了IPriducerConsumerCollection<T>接口.这个接口中最重要的方法是TryAdd()和TryTake().TryAdd()方法尝试给集合添加一项,但如果集合禁止添加项,这个操作可能失败.为了给出相关信息,TryAdd()方法返回一个布尔值,以说明操作是成功还是失败.TryTake()方法也以这种方式工作,以通过调用者操作是成功还是失败,并在操作成功时返回集合中的项.

C#编程(五十八)----------并行集合的更多相关文章

  1. 学习ASP.NET Core Razor 编程系列十八——并发解决方案

    学习ASP.NET Core Razor 编程系列目录 学习ASP.NET Core Razor 编程系列一 学习ASP.NET Core Razor 编程系列二——添加一个实体 学习ASP.NET ...

  2. C#编程(五十九)----------集合的性能

    各种集合的性能 许多集合类提供了相同的功能,例如,SortedList类与SortedDictionary类的功能几乎完全相同.但是,其性能常常有很大的区别.SortedList集合使用的内存少,So ...

  3. 五十八、linux 编程——UDP 编程 广播

    58.1 广播介绍 58.1.1 介绍 广播实现一对多的通讯 它通过向广播地址发送数据报文实现的 58.1.2 套接字选项 套接字选项用于修饰套接字以及其底层通讯协议的各种行为.函数 setsocko ...

  4. Coding and Paper Letter(五十八)

    资源整理. 1 Coding: 1.支持TMS.WMTS标准瓦片下载,支持百度地图瓦片.高德地图瓦片.腾讯地图瓦片.天地图.ArcServer Rest瓦片.ArcServer本地缓存切片.geose ...

  5. C#高级编程五十四天----Lookup类和有序字典

    Lookup类 Dictionary<Tkey,TValue>仅仅为每一个键支持一个值.新类Lookup<Tkey,TValue>是.NET3.5中新增的,它类似与Dictio ...

  6. JavaEE基础(十八)/集合

    1.集合框架(Map集合概述和特点) A:Map接口概述 查看API可以知道: 将键映射到值的对象 一个映射不能包含重复的键 每个键最多只能映射到一个值 B:Map接口和Collection接口的不同 ...

  7. Java开发笔记(五十八)简单接口及其实现

    前面介绍了抽象方法及抽象类的用法,看似解决了不确定行为的方法定义,既然叫唤动作允许声明为抽象方法,那么飞翔.游泳也能声明为抽象方法,并且鸡类涵盖的物种不够多,最好把这些行为动作扩展到鸟类这个群体,于是 ...

  8. 五十八 数据库访问使用SQLite

    SQLite是一种嵌入式数据库,它的数据库就是一个文件.由于SQLite本身是C写的,而且体积很小,所以,经常被集成到各种应用程序中,甚至在iOS和Android的App中都可以集成. Python就 ...

  9. python核心编程五——映像和集合

    1.字典 不同意一个键相应多个值:当有键发生冲突(即.字典键反复赋值),取最后(近期)的赋值. >>> dict1 = {' foo':789, 'foo': 'xyz'}     ...

随机推荐

  1. Centos 6.9 安装Rabbitmq

    一.安装Rabbitmq 首先安装编译工具 yum -y install make gcc gcc-c++ kernel-devel m4 ncurses-devel openssl-devel Er ...

  2. linux下安装redis及其中遇到的问题的解决方法

    1.将下载好的压缩包放到/usr/local目录下# tar xzf redis-3.0.2.tar.gz # cd redis-3.0.2 # make 提示错误 make: cc: Command ...

  3. tidb 升级步骤

    1.检查ansible版本,正常情况下,2.1 rc3需要兼容ansible 2.5以上的版本 $ ansible --version 2.检查python两个模块jinja2需要升级到2.9.6或以 ...

  4. spark优化之并行度

    这个其实我前面已经记录过了,这里在记录一下. 我可以通过参数人为的来控制分区大小,增加分区中即可增加任务的并行度,并行度高自然运行的就快了嘛. 官方推荐集群中每个cpu并行的任务是2-3个(也就是2- ...

  5. Unit的各种断言

    今天遇到这个问题,就值得自己总结一下. 1.介绍 JUnit为我们提供了一些辅助函数,他们用来帮助我们确定被测试的方法是否按照预期的效果正常工作,通常,把这些辅助函数称为断言.下面我们来介绍一下JUn ...

  6. 怎么去除移动端点击a标签链接时的背景色

    在手机端点击链接时会发现有一个背景色,有时候需要改变这个颜色,或者去除这个颜色,有时候a标签做成按钮时这个颜色的存在会很丑,像这样: 可以通过 -webkit-tap-highlight-color: ...

  7. Ansible专题整理

    Ansible 专题文章总览 Ansible小手册,仅供参考 文章如未明确说明实验环境,默认如下: OS:Centos 6.7 x86_64 Ansible: 2.1.2.0 Python: 2.6. ...

  8. Windows密码破解工具ophcrack

    Windows密码破解工具ophcrack   Windows用户密码都采用哈希算法加密进行保存.Kali Linux内置了专用破解工具ophcrack.该工具是一个图形化界面工具,支持Windows ...

  9. Bzoj2534:后缀自动机 主席树启发式合并

    国际惯例的题面:考虑我们求解出字符串uvu第一个u的右端点为i,第二个u的右端点为j,我们需要满足什么性质?显然j>i+L,因为我们选择的串不能是空串.另外考虑i和j的最长公共前缀(也就是说其p ...

  10. 使用NewLife网络库构建可靠的自动售货机Socket服务端(一)

    最近有个基于tcp socket 协议和设备交互需求,想到了新生命团队的各种组件,所以决定用NewLife网络库作为服务端来完成一系列的信息交互. 第一,首先说一下我们需要实现的功能需求吧 1,首先客 ...