只要让应用程序同时执行多项任务,就要用到并发。
注意:
在现代应用程序中,直接使用低层级的线程类型几乎毫无价值,但与传统的多线程相比,高层级抽象更为强大、高效。
因此,对应已然过时的技术,本系列的多线程方法均不会赘述也不使用Thread类型或BackgroundWorker类型,它们已经有了更高高级的代替方案。
多线程是一种并发形式,但并发唯一的形式。
并行处理/并行编程,通过多线程最大化地利用多个处理器核心(每个线程都由格子的核心运行)。并行处理/编程是一种多线程形式,而多线程是一种并发形式。
future(或promise)是一种类型,代表了某种会在将来完成的操作。
.NET中的future类型有Task和Task
异步编程的核心思想是异步操作,也就是说,某个操作已经开始,但一段时间后才会去完成。虽然该操作已经在执行中,但它并不会阻塞原来的线程,而且启动该操作的线程依旧可以自由地进行其他工作。当该操作完成时,它便告知相关future,或者调用其回调或者事件,让应用程序知晓该操作已经完成了。
异步编程是一种强大的并发形式,需要几位复杂的代码。
但是async和await使得异步编程几乎变得和同步一样简单。
响应式编程是另一种并发形式,它是基于异步事件,而非异步操作。
异步事件不见得有一个正在意义上的”开始“,它可能会在任何事件发生,可能多次发生,比如用户的输入。
响应式编程并不一定是并发的,但它与并发密切相关。
在声明方法时,添加async关键字。它会发挥两重用途:
激活该方法种的await关键字,并知会编译器为该方法生成一个状态机,类似于yield return的工作方式。如果aysnc方法有返回值,那么这个之可能是Task
此外,若async方法以一组枚举返回多个值,它便会返回IAsyncEnumberable
注意:
只要在编写async事件处理程序时,才需要使用async方法来返回void。
无返回值的常规async方法都应当返回Task,而非void。
await关键字并不仅限于处理任务,它也可以处理任何特定格式的可等待对象。
例如:ValueTask
但在大多数情况下,await处理的时Task或Task
两种方法来创建Task实例。
(1)某些任务代表的是CPU需要执行的实际代码,这些需要调用Task.Run来创建这些运算的任务。但如果要做某个特定的调度器上运行这些任务,那么需要调用Task.Factory.StartNew。
(2)另一些任务代表的是通知,创建这种基于事件的任务应当采用TaskCompletionSource
并行编程可以提交客户端系统的CPU利用率。
但对服务器端系统而言,这通常并不适用。大多数服务器拥有并行机制,比如,ASP.NET就会并行处理多个请求。
但在某些情况下(假如一直并发用户的数量始终较低),在服务器上编写并行代码可能仍旧有用。但总体来看,服务器上的并行编程会与其内置的并行机制冲突,因而不会代理任何实际的益处。
并行机制分为数据并行和任务并行。
数据并行:当有一堆数据项需要处理,而且每一份