只要我们需要程序同时干多件事情,dotNET每日精

作者: 编程  发布:2019-11-05

并发编程的术语

  • 并发
    同时做多件事情
  • 多线程
    并发的一种形式,它采用多个线程来执行程序。
    多线程是并发的一种形式,但不是唯一的形式。
  • 并行处理
    把正在执行的大量的任务分割成小块,分配给多个同时运行的线程。
    并行处理是多线程的一种,而多线程是并发的一种。
  • 异步编程
    并发的一种形式,它采用future模式或回调(callback)机制,以避免产生不必要的线程。
    一个 future(或 promise)类型代表一些即将完成的操作。在 .NET 中,新版 future 类型有 Task 和 Task 。在老式异步编程 API 中,采用回调或事件(event),而不是future。异步编程的核心理念是异步操作(asynchronous operation):启动了的操作将会在一段时间后完成。这个操作正在执行时,不会阻塞原来的线程。启动了这个操作的线程,可以继续执行其他任务。当操作完成时,会通知它的 future,或者调用回调函数,以便让程序知道操作已经结束。
  • 响应式编程
    一种声明式的编程模式,程序在该模式中对事件做出响应。
    响应式编程的核心理念是异步事件(asynchronous event):异步事件可以没有一个实际的“开始”,可以在任何时间发生,并且可以发生多次,例如用户输入。
    如果把一个程序看作一个大型的状态机,则该程序的行为便可视为它对一系列事件做出响应,即每换一个事件,它就更新一次自己的状态。

在并发编程中我们经常听到以下一些概念,今天我将尝试进行阐述。

(此文章同时发表在本人微信公众号“dotNET每日精华文章”,欢迎右边二维码来关注。)

异步编程的两个好处

  1. 对于面向终端用户的 GUI 程序:异步编程提高了响应能力。面对在运行时被临时锁定界面的程序,异步编程可以使程序在此时仍能流畅的响应用户的输入。譬如:WPF界面,执行一个需要等待的操作时,仍可以点击输入框进行填写,而不会出现卡顿,无法点击的情况或者对页面无法进行拖拽。
  2. 对于服务器端应用:异步编程实现了可扩展性。服务器应用可以利用线程池满足其可扩展性,使用异步编程后,可扩展性通常可以提高一个数量级。即提高服务器端应用的TPS(Transactions Per Second)和 QPS (Queries Per Second)

一、并发

题记:就语言和运行时层面,C#做并发编程一点都不弱,缺的是生态和社区。

Atitit.并发编程原理与概论 attilax总结

并行的两种形式

并行编程的使用场景:需要执行大量的计算任务,并且这些任务能分割成相互独立的任务块儿

并行的形式有两种:数据并行(data parallelism)和任务并行(task parallelim)。

数据并行(data parallelism):有大量的数据需要处理,并且每一块数据的处理过程基本上是彼此独立的。

任务并行(task parallelim):需要执行大量任务,并且每个任务的执行过程基本上是彼此独立的。任务并行可以是动态的,如果一个任务的执行结果会产生额外的任务,这些新增的任务也可以加入任务池。

实现数据并行的方法

  • Parallel.ForEach
  • PLINQ(Parallel LINQ)

每个任务块要尽可能的互相独立。 只要任务块是互相独立的,并行性就能做到最大化。一旦你在多个线程中共享状态,就必须以同步方式访问这些状态,那样程序的并行性就变差了。

数据并行重点在处理数据,任务并行则关注执行任务。

实现任务并行的方法

  • Parallel.Invoke
  • Task.Wait

通常情况下,没必要关心线程池处理任务的具体做法。数据并行和任务并行都使用动态调整的分割器,把任务分割后分配给工作线程。线程池在需要的时候会增加线程数量。线程池线程使用工作窃取队列(work-stealing queue)。

同时干多件事情,这就是并发的作用。

硅谷才女朱赟(我的家门)昨天发了一篇文章《为什么用 Java —— 关于并发编程》,让大家学习了Java中如何进行并发编程的一些基本知识。作为一个将近15年的.NET程序员,我觉得有必要给大家补充介绍一下C#进行并发编程的知识(当然不会太深入讲解)。这篇文章无意进行技术比较,毕竟技术只是工具(大同小异,各有千秋),主要还是看用工具的人。

 

响应式编程Rx学习难度较大

使用场景:处理的事件中带有参数,最好采用响应式编程
响应式编程的核心概念是:可观察的流(observable stream)
响应式编程的最终代码非常像 LINQ,可以认为它就是“LINQ to events”,它采用“推送”模式,事件到达后就自行穿过查询。

web服务器可以利用并发同时处理大量用户的请求。

并发(英文Concurrency),其实是一个很泛的概念,字面意思就是“同时做多件事”,不过方式有所不同。在.NET的世界里面,并发一般涉及如下几个方面:

 

TPL数据流

异步编程和并行编程这两种技术结合起来就是TPL数据流
数据流网格的基本组成单元是数据流块(dataflow block)。

Rx 和 TPL有很多相同点。
网格和流都有“数据项”这一概念,数据项从网格或流的中间穿过。还有,网格和流都有“正常完成”(表示没有更多数据需要接收时发出的通知)和“不正常完成”(在处理数据中发生错误时发出的通知)这两个概念。但是,Rx 和 TPL 数据流的性能并不相同。

当需要执行需要计时的任务,最佳选择是Rx的 可观察流 observable 对象
当需要进行并行处理,最佳选择是 TPL数据流块

只要我们需要程序同时干多件事情,我们就需要并发。

  1. 多线程编程(已过时,不介绍)
  2. 异步编程
  3. 并行编程
  4. 响应式编程
  5. 数据流编程

1. 并发一般涉及如下几个方面:2

线程和线程池

线程是一个独立的运行单元,每个进程内部有多个线程,每个线程可以各自同时执行指令。每个线程有自己独立的栈,但是与进程内的其他线程共享内存。
对某些程序来说,其中有一个线程是特殊的,例如用户界面程序有一个 UI 线程,控制台程序有一个 main 线程。

每个 .NET 程序都有一个线程池,线程池维护着一定数量的工作线程,这些线程等待着执行分配下来的任务。线程池可以随时监测线程的数量。配置线程池的参数多达几十个,但是建议采用默认设置,线程池的默认设置是经过仔细调整的,适用于绝大多数现实中的应用场景。

二、多线程

为了支持以上编程,.NET提供了很多基础功能,比如:委托,匿名函数,Lambda表达式,线程池,Task模型,支持并发的集合(线程安全集合和不可变集合) ,调度器,同步功能。在这里,就不对这些内容进行介绍了,大家可以自行搜索学习。另外,对于Actor模型,.NET中也有支持,但我不认为它属于语言/运行时层面的并发,它更像架构层面的并发,我最后会简单介绍。

2. 线程安全性 ( 2.2 原子性    2.3 加锁机制2

并发编程的设计原理

大多数并发编程技术有一个类似点:它们本质上都是函数式(functional)的。函数式编程理念是并发编程的本质。

并发编程的一种形式,其采用多个线程执行程序。

1,异步编程

异步编程就是使用future模式(又称promise)或者回调机制来实现(Non-blocking on waiting)。

如果使用回调或事件来实现(容易callback hell),不仅编写这样的代码不直观,很快就容易把代码搞得一团糟。不过在.NET 4.5(C# 5)中引入的async/await关键字(在.NET 4.0中通过添加Microsoft.Bcl.Async包也可以使用),让编写异步代码变得容易和优雅。通过使用async/await关键字,可以像写同步代码那样编写异步代码,所有的回调和事件处理都交给编译器和运行时帮你处理了。

使用异步编程有两个好处:不阻塞主线程(比如UI线程),提高服务端应用的吞吐量。所以微软推荐ASP.NET中默认使用异步来处理请求。

要详细了解异步编程,可以参考官方文档:和《Async in C# 5.0》这本书。另外,在这个官方文档中,微软还特意把异步编程分作了3种不同的模型:基于任务的模式(TAP)就是我上面推荐的这种,基于事件的模式(EAP)和异步编程模型(APM)我上面不推荐的事件和回调。

2.1. 线程封闭3.3.1Ad-hoc线程封闭   3.3.2 栈封闭   3.3.3ThreadLocal类2

线程是一个独立的运行单元,每个进程内部有多个线程,每个线程可以各自同时执行指令。

2,并行编程

并行编程的出现实际上是随着CPU有多核而兴起的,目的是充分利用多核CPU的计算能力。并行编程由于会提高CPU的利用率,更适合客户端的一些应用,对于服务端的应用可能会造成负面影响(因为服务器本身就具有并行处理的特点,比如IIS会并行的处理多个请求)。我自己使用并行编程最多的场景是之前分析环境数据不确定度的时候,使用并行的方式计算蒙特卡洛模拟(计算上千次之后拟合),当然后来我使用泰勒级数展开来计算不确定度,没有这么多的计算量就无需并行了。当然在计算多方案结果比较的情况下,还是继续使用了并发计算。

在.NET中,并行的支持主要靠.NET 4.0引入的任务并行库和并行LINQ。通过这些库可以实现数据并行处理(处理方式相同,输入数据不同,比如我上面提到的应用场景)或者任务并行处理(处理方式不同,且数据隔离)。通过使用并行处理库,你不用关心Task的创建和管理(当然更不用说底层的线程了),只需要关注处理任务本身就行了。

具体的用法还是参考官方文档:,当然《Parallel Programming with Microsoft .NET》这本书也行。

3. 异步2

每个线程有自己独立的栈,但是与进程内的其他线程共享内存。

3,响应式编程

响应式编程最近成为了一个Buzzword,其实微软6年前就开始给.NET提供一个Reactive Extensions了。一开始要理解响应式编程有点困难,但是一旦理解了,你就会对它的强大功能爱不释手。简单来说,响应式编程把事件流看作数据流,不过数据流是从IEnumable中拉取的,而事件流是从IObservable推送给你的。为什么响应式编程可以实现并发呢?这是因为Rx做到线程不可知,每次事件触发,后续的处理会从线程池中任意取出一个线程来处理。且可以对事件设置窗口期和限流。举个例子,你可以用Rx来让搜索文本框进行延迟处理(而不用类似我很早的时候用个定时器来延迟了)。

要详细了解Rx最好的方式就是浏览 IntroToRx.com 这个网站,当然还有官方文档:。

4. 同步与锁关键字2

线程池是线程更广泛的一种应用形式,其维护着一定数量的工作线程,这些线程等待着执行分配下来的任务。线程池可以随时监测线程的数量

4,数据流编程

数据流(DataFlow)编程可能大家就更陌生了,不过还是有些常用场景可以使用数据流来解决。数据流其实是在任务并行库(TPL)上衍生出来的一套处理数据的扩展(也结合了异步的特性),TPL也是处理并行编程中任务并行和数据并行的基础库。

望文生义,TPL DataFlow就是对数据进行一连串处理,首先为这样的处理定义一套网格(mesh),网格中可以定义分叉(fork)、连接(join)、循环(loop)。数据流入这样的处理网格就能够并行的被处理。你可以认为网格是一种升级版的管道,实际上很多时候就是被当作管道来使用。使用场景可以是“分析文本文件中词频”,也可以是“处理生产者/消费者问题”。

参考资料当然也是官方文档:。

5. 5.2 并发容器与并发集合2

线程池催生了另外一种重要的并发形式:并行处理。

5,Actor模型

Scala有Akka,其实微软研究院也推出了Orleans来支持了Actor模型的实现,当然也有Akka.NET可用。Orleans设计的目标是为了方便程序员开发需要大规模扩展的云服务, 可用于实现DDD+EventSourcing/CQRS系统。

官方网站是:,善友也有介绍:

那么,我为什么喜欢使用C#来做并发编程呢?显而易见,有上面这些唾手可得的工具,使用C#同样可以轻易开发并发程序。

6. Future模式 2

多线程并不是并发编程的唯一形式,虽然.NET和Java等语言框架都对底层线程类型提供了支持,但是对开发人员并不友好,最新的.NET和Java

7. 5.3 阻塞队列和生产者-消费者模式(5.3.2 串行线程封闭 5.3.3 双端队列与工作密取 2

都提供了更高级别的抽象,让我们开发并发程序更加方便高效。

8. 5.4 阻塞方法与中断方法 2

三、并行处理

9. 5.5 同步工具类 5.5.1 闭锁 5.5.2FutureTask5.5.3 信号量 5.5.4 栅栏 3

将大块的任务分割成相互独立的小块,并分配给多个同时运行的线程处理。

10. 5.6 构建高效且可伸缩的结果缓存3

并行处理采用多线程,提高了处理器的利用效率。

11. 线程池3

并行编程通常不适合服务器系统,服务器本身都具有并发处理能力。

12. 7.1 任务取消3

数据并行可以处理大量的彼此独立的数据,比如Hadoop等大数据处理框架。

13. 任务并行库(TPL) 4

任务并行可以将彼此独立的拆分任务同时执行。

14. 死锁的避免与诊断4

下边看下.NET中提供的并行编程

15. 原子变量与非阻塞同步机制4

使用Parallel.ForEach进行数据并行

16. 协程4

void RotateMatrices(IEnumerable<Matrix> matrices, float degrees)
{
    Parallel.ForEach(matrices, matrix => matrix.Rotate(degrees));
}

17. 异步、多线程、任务、并行的本质4

 

18. 现在,该用什么来编写多线程 5

使用Parallel.ForEach进行数据并行

18.1.1. 1,异步编程5

IEnumerable<bool> PrimalityTest(IEnumerable<int> values)
{
    return values.AsParallel().Select(val => IsPrime(val));
}

19. 响应式编程6

 

20. ,数据流编程6

数据的独立性是并行性最大化的前提,否为了确保安全性就需要引入同步,从而影响程序的并行程度。

20.1. 5,Actor模型7

只能最大程度的并行,但是总是消灭不了同步,数据并行的结果总是需要进行聚合,Parallel实现了响应的重载及map/reduce函数。

21. Qa7

Parallel类的Invoke方式可以实现任务并行

22. Java c# .net c++的并发技术7

9159.com 1

22.1. Java并发编程实战(第16届Jolt大奖提名图书,Java并发编程必读佳作8

void ProcessArray(double[] array)
{
    Parallel.Invoke(
        () => ProcessPartialArray(array, 0, array.Length / 2),
        () => ProcessPartialArray(array, array.Length / 2, array.Length)
    );
}
void ProcessPartialArray(double[] array, int begin, int end)
{
    // CPU 密集型的操作......
}        

22.2. Java并发技术8

9159.com 2

22.3. 《C#多线程编程实战( ((美...【8

 

22.4. Line 278:   《C++并发编程实战》 Line 285: 第1章 你好,C++并发世界9

 

22.5. 《C#并发编程经典实例》9

任务并行也依赖任务的独立性,同时要注意闭包对变量的引用,即使是值类型也是引用。

1. 并发一般涉及如下几个方面:

1. 多线程编程(已过时,不介绍)

2. 异步编程

3. 并行编程

4. 响应式编程

5. 数据流编程

 

任务不要特别短,也不要特别长。如果任务太短,把数据分割进任务和在线程池中调度任务的开销会很大。如果任务太长,线程池就不能进行

2. 线程安全性 ( 2.2 原子性    2.3 加锁机制

 

有效的动态调整以达到工作量的平衡。

2.1. 线程封闭3.3.1Ad-hoc线程封闭   3.3.2 栈封闭   3.3.3ThreadLocal类

 

 

3. 异步

四、异步编程

4. 同步与锁关键字

并发编程的一种形式,它采用future模式或者回调(callback)机制,以避免产生不必要的线程。

5. 5.2 并发容器与并发集合

回调和事件作为老式的异步编程,在服务器端和GUI中都有广泛的应用。

6. Future模式

作者:: 绰号:老哇的爪子 ( 全名::Attilax Akbar Al Rapanui 阿提拉克斯 阿克巴 阿尔 拉帕努伊 ) 

汉字名:艾提拉(艾龙),   EMAIL:1466519819@qq.com

转载请注明来源: 

 

一个future或者promise代表一些即将完成的操作,在.NET中的TPL中有Task和Task<TResult>,在Java中有FutureTask,在JS中有fetch(新版Firefox

7. 5.3 阻塞队列和生产者-消费者模式(5.3.2 串行线程封闭 5.3.3 双端队列与工作密取

和Chorm支持)。

8. 5.4 阻塞方法与中断方法

异步编程可以在启动一个操作之后,可以继续执行而不会被阻塞,待操作执行完之后,通知future或者执行回调函数,以便告知操作结束。

9. 5.5 同步工具类 5.5.1 闭锁 5.5.2 FutureTask   5.5.3 信号量 5.5.4 栅栏

异步编程是一种功能强大的并发形式,但传统的异步编程特别复杂而且不易于代码维护。.NET和Node.JS支持的async和await,让异步编程变得

10. 5.6 构建高效且可伸缩的结果缓存

跟串行编程一样简单。

11. 线程池

第8章 线程池的使用
8.1 在任务与执行策略之间的隐性耦合
8.1.1 线程饥饿死锁
8.1.2 运行时间较长的任务
8.2 设置线程池的大小
8.3 配置ThreadPoolExecutor
8.3.1 线程的创建与销毁
8.3.2 管理队列任务
8.3.3 饱和策略
8.3.4 线程工厂

 

 

 

12. 7.1 任务取消

7.1.1 中断
7.1.2 中断策略
7.1.3 响应中断
7.1.4 示例:计时运行
7.1.5 通过Future来实现取消
7.1.6 处理不可中断的阻塞
7.1.7 采用newTaskFor来封装非标准的取消
7.2 停止基于线程的服务
7.2.1 示例:日志服务
7.2.2 关闭ExecutorService
7.2.3 “毒丸”对象
7.2.4 示例:只执行一次的服务
7.2.5 shutdownNow的局限性
7.3 处理非正常的线程终止

下面看下.NET 的两个关键字: async 和 await 。 async 关键字加在方法声明上,它的主要目的是使方法内的 await 关键字生效。如果 async 方法有

13. 任务并行库(TPL)

返回值,应返回 Task<T> ;如果没有返回值,应返回 Task 。这些task 类型相当于 future,用来在异步方法结束时通知主程序。下边的例子同时请求两

14. 死锁的避免与诊断

个服务地址,只要有一个返回结果即可完成。

15. 原子变量与非阻塞同步机制

 

16. 协程

9159.com 3

17. 异步、多线程、任务、并行的本质

9159.com,这四个概念对应在CLR中的本质,本质都是多线程。

异步,简单的讲就是BeginInvoke、EndInvoke模式,它在CLR内部线程池进行管理;

多线程,体现在C#中,可以由类型Thread发起。也可以由ThreadPool发起。前者不受CLR线程池管理,后者则是。FCL团队为了各种编程模型的方便,还另外提供了BackgroundWorker和若干个Timer,基本上它们都是ThreadPool的加强,增加了一些和调用者线程的交互功能;

任务(Task),为FCL4.0新增的功能,在一个称之为任务并行库(TPL)的地方,其实也就是System.Threading.Tasks命名空间下。任务并行库名字取的很玄乎,其实它也是CLR线程池的加强。优化了线程间的调度算法,增加了和调用者线程的交互功能;

并行(Parallel),为FCL4.0新增的功能,也属于TPL。并行在后台使用Task进行管理,说白了,因为Task使用的线程池线程,所以Parallel自然使用的也是线程池线程进行管理,它的本质仅仅是进一步简化了Task。在这里要增进一个对于并行的理解。实际上,多线程天然就是并行的。及时不用任务并行库,用Thread类型新起两个线程,CLR或者说Windows系统也会将这两个线程根据需要安排到两个CPU上去执行。所以,并不是因为多了任务并行库,CLR才支持并行计算,任务并行库只是提供了一组API,使我们能够更好的操纵线程进行并行开发而已。

 

// 返回第一个响应的 URL 的数据长度。
private static async Task<int> FirstRespondingUrlAsync(string urlA, string urlB)
{
    var httpClient = new HttpClient();
    // 并发地开始两个下载任务。
    Task<byte[]> downloadTaskA = httpClient.GetByteArrayAsync(urlA);
    Task<byte[]> downloadTaskB = httpClient.GetByteArrayAsync(urlB);
    // 等待任意一个任务完成。
    Task<byte[]> completedTask =
    await Task.WhenAny(downloadTaskA, downloadTaskB);
    // 返回从 URL 得到的数据的长度。
    byte[] data = await completedTask;
    return data.Length;
}

18. 现在,该用什么来编写多线程 

如果你在FRAMEWORK4.0下编写代码,那么应该按照这个优先级来撰写多线程代码: 

优先

次优先

不得以

Parallel(含扩展库PLinq)

Task

ThreadPool(BackgroundWorker,Timer)

异步

Thread

这个表满足了大部分情况下的一个优先级指导,但在某些情况下会有例外。

多线程编程(已过时,不介绍)

9159.com 4

18.0.1. 1,异步编程

异步编程就是使用future模式(又称promise)或者回调机制来实现(Non-blocking on waiting)。

微软还特意把异步编程分作了3种不同的模型:基于任务的模式(TAP)就是我上面推荐的这种,基于事件的模式(EAP)和异步编程模型(APM)我上面不推荐的事件和回调。

 

 

19. 响应式编程

响应式编程最近成为了一个Buzzword,其实微软6年前就开始给.NET提供一个Reactive 
Extensions
了。一开始要理解响应式编程有点困难,但是一旦理解了,你就会对它的强大功能爱不释手。简单来说,响应式编程把事件流看作数据流,不过数据流是从IEnumable中拉取的,而数据流是从IObservable推送给你的。为什么响应式编程可以实现并发呢?这是因为Rx做到线程不可知,每次事件触发,后续的处理会从线程池中任意取出一个线程来处理。且可以对事件设置窗口期和限流。举个例子,你可以用Rx来让搜索文本框进行延迟处理(而不用类似我很早的时候用个定时器来延迟了)。

 

20. ,数据流编程

数据流(DataFlow)编程可能大家就更陌生了,不过还是有些常用场景可以使用数据流来解决。数据流其实是在任务并行库(TPL)上衍生出来的一套处理数据的扩展(也结合了异步的特性),TPL也是处理并行编程中任务并行和数据并行的基础库。

望文生义,TPL DataFlow就是对数据进行一连串处理,首先为这样的处理定义一套网格(mesh),网格中可以定义分叉(fork)、连接(join)、循环(loop)。数据流入这样的处理网格就能够并行的被处理。你可以认为网格是一种升级版的管道,实际上很多时候就是被当作管道来使用。使用场景可以是“分析文本文件中词频”,也可以是“处理生产者/消费者问题”。

 

五、响应式编程

20.1. 5,Actor模型

Scala有Akka,其实微软研究院也推出了Orleans来支持了Actor模型的实现,当然也有Akka.NET可用。Orleans设计的目标是为了方便程序员开发需要大规模扩展的云服务,

 

 

一种声明式的编程模式,程序在该模式中对事件进行响应。

21. Qa

.2:何时用异步,何时用线程或线程池

这需要从“IO操作的DMA(Direct Memory Access)模式”讲起。通过DMA的数据交换几乎可以不损耗CPU的资源。在硬件部分,硬盘、网卡、声卡、显卡等都有DMA功能。可以简单的认为,当我们的工作线程需要操作I/O资源的时候(如读取一个大文件、读取一个网页、读取Socke包等),我们就需要用异步去做这些事情。异步模式只会在工作开始以及工作结束的时候占用CLR线程池,其它时候由硬盘、网卡等硬件设备来处理具体的工作,这就不会过多占用到CPU空间和时间损耗。 

概括而言:

计算密集型工作,直接采用线程;

IO密集型工作,采用异步机制;

当我们不清楚什么工作是I/O密集型的,一个不是很恰当的指导就是:查看FCL类型成员,如果成员提供了类似BeginDosomething方法的,则优先使用它,而不是新起一个线程或丢到线程池。

 

3.4:何时用Thread 
以上的各种线程模型,它们最终都是Thread。 那么什么时候需要Thread直接出场呢?

最重要的使用Thread的理由是,我们需要控制线程的优先级。Thread之上的线程模型都不支持优先级设置。设置一个线程的高优先级可以使它获得更多的CPU时间;

再者,可以控制线程为前台线程。当然,由Thread新起的线程默认就是前台线程。前台线程不随着调用者线程的中断而中断,这使得我们可以用Thread来进行一些关键性的操作。

 

程序针对不同的事件进行响应并更新自己的状态。

22. Java c# .net c++的并发技术

异步编程针对启动的操作,响应编程针对可以任何事件重复发生的异步事件。

22.1. Java并发编程实战(第16届Jolt大奖提名图书,Java并发编程必读佳作

作者:Brian Goetz,Tim Peierls,Joshua Bloch,Joseph Bowbeer,David Holmes,Doug Lea 著,童云兰 等译

 

 

第1章 简介

 第2章 线程安全性

 第3章 对象的共享

 第4章 对象的组合

 第5章 基础构建模块

 第6章 任务执行

 第7章 取消与关闭

 第8章 线程池的使用

 第9章 图形用户界面应用程序

 第10章 避免活跃性危险

 第11章 性能与可伸缩性

 第12章 并发程序的测试

 第13章 显式锁

 第14章 构建自定义的同步工具

 第15章 原子变量与非阻塞同步机制

 第16章 Java内存模型

 

 

响应式编程基于“可观察的流”(observable stream)。一旦申请了可观察流,就可以收到任意数量的数据项( OnNext ),并且流在结束时会发出一个错误(

22.2. Java并发技术

Executor框架

 

OnError )或一个结束的通知( OnCompleted )。实际的接口如下

22.3. 《C#多线程编程实战( ((美...【 

第1章 线程基础 ( lock关键字 1.11 使用Monitor类锁定资源
 第2章 线程同步
 第3章 使用线程池
第4章 使用任务并行库
第5章 使用C# 5.0
第6章 使用并发集合
第7章 使用PLINQ
第8章 使用Reactive Extensions
第9章 使用异步I/O
第10章 并行编程模式
第11章 更多信息

 

9159.com 5

22.4. Line 278:   《C++并发编程实战》 Line 285: 第1章 你好,C++并发世界 

Line 300: 第2章 管理线程

Line 311: 第3章 在线程间共享数据

Line 329: 第4章 同步并发操作

Line 348: 第5章 C++内存模型和原子

Line 370: 第6章 设计基于锁的并发数据结构

Line 380: 第7章 设计无锁的并发数据结构

 

interface IObserver<in T>
{
    void OnNext(T item);
    void OnCompleted();
    void OnError(Exception error);
}

interface IObservable<out T>
{
    IDisposable Subscribe(IObserver<T> observer);
}

22.5. 《C#并发编程经典实例》

 第1 章 并发编程概述  

第2 章 异步编程基础  

第3 章 并行开发的基础  

第4 章 数据流基础  

第5 章 Rx 基础  

第6 章 测试技巧  

第7 章 互操作  

第8 章 集合  

第9 章 取消  

第10 章 函数式OOP

第11 章 同步  

第12 章 调度  

第13 章 实用技巧  

参考资料

异步、多线程、任务、并行编程之一:选择合适的多线程模型

  • Luminji - 博客园.html

我为什么喜欢用C#来做并发编程-博客-云栖社区-阿里云.html

 

atiend

9159.com 6

 

微软的 Reactive Extensions(Rx)库已经实现了所有接口。下面的代码中,前面是我们不熟悉的操作符( Interval 和 Timestamp ),最后是一个 Subscribe ,

但是中间部分是我们在 LINQ 中熟悉的操作符: Where 和 Select 。LINQ 具有的特性,Rx也都有。Rx 在此基础上增加了很多它自己的操作符,特别

是与时间有关的操作符:

Observable.Interval(TimeSpan.FromSeconds(1))
.Timestamp()
.Where(x => x.Value % 2 == 0)
.Select(x => x.Timestamp)
.Subscribe(x => Trace.WriteLine(x));

 

上面的代码中,首先是一个延时一段时间的计数器( Interval ),随后、后为每个事件加了一个时间戳( Timestamp )。接着对事件进行过滤,只包含偶数

值( Where ),选择了时间戳的值( Timestamp ),然后当每个时间戳值到达时,把它输入调试器( Subscribe )。可观察流的定义和其订阅是互相独立的。

上面最后一个例子与下面的代码等效:

9159.com 7

IObservable<DateTimeOffset> timestamps =
Observable.Interval(TimeSpan.FromSeconds(1))
.Timestamp()
.Where(x => x.Value % 2 == 0)
.Select(x => x.Timestamp);
timestamps.Subscribe(x => Trace.WriteLine(x));

9159.com 8

 

一种常规的做法是把可观察流定义为一种类型,然后将其作为 IObservable<T> 资源使用。其他类型可以订阅这些流,或者把这些流与其他操作符

组合,创建另一个可观察流Rx 的订阅也是一个资源。 Subscribe 操作符返回一个 IDisposable ,即表示订阅完成。当你响应了那个可观察流,就得处

理这个订阅。对于hot observable(热可观察流)和 cold observable(冷可观察流)这两种对象,订阅的做法各有不同。一个 hot observable 对象是指一直

在发生的事件流,如果在事件到达时没有订阅者,事件就丢失了。例如,鼠标的移动就是一个 hot observable 对象。cold observable 对象是始终没有

输入事件(不会主动产生事件)的观察流,它只会通过启动一个事件队列来响应订阅。例如,HTTP 下载是一个 cold observable 对象,只有在订阅后

才会发出 HTTP 请求。

六、并发集合和不可变集合

大多数并发集合通过快照,既可以确保一个线程修改数据,同时也可以允许多个线程同时枚举数据。

不可变集合的无法修改性确保了所有操作的简洁性,特别适合在并发编程中使用。

七、并发编程与函数编程

大多数并发编程技术本质上都是函数式(functional) 的。

函数式编程理念简化并发编程的设计。每一个并行的片段都有输入和输出。他们不依赖于全局(或共享)变量,也不会修改全局(或共享)数据结构。

函数式编程的数据不变性在确保并发安全性的前提下,同时也防止了并发的活跃性问题。

 

本文由9159.com发布于编程,转载请注明出处:只要我们需要程序同时干多件事情,dotNET每日精

关键词:

上一篇:没有了
下一篇:没有了