C# 并行编程的一点总结
Thread和Task
并行编程很多时候也被称为多线程编程模式,这个多线程说说明了并行编程的本质定义,就是创建多个线程,去并行执行一些任务,从而达到更好的性能。 这里的多线程,一般都是指操作系统中的线程概念。一般的编程语言平台,比如C++和C#,都会有相应的创建线程,调度线程,销毁线程的方法。在C#中就用Thread来实现的。但是我这里想重点提出的,不是线程,而是C#中特有的Task。简单来说,Task就是CLR帮你在线程之上又做了一层抽象。CLR会维护一个线程池来执行Task,开发者就不需要管理线程了。因为操作系统中的线程还是很贵的(虽然比进程便宜多了),每个线程需要维护自己的栈,线程之间的切换也需要额外的CPU开销。所以除非有特殊的需求,在一般的C#程序开发中使用Task是更好的选择。
async/await
在.NET 4.5 里引入的async/await两个关键词应该是最常见的和Task相关的方法(工具)了。关于async/await的具体实现我这里就不展开了,简单来理解的话,async用来定义一个方法是awaitable的类型,而当程序执行到await的时候,当前的Task会被挂起,CLR会创建的一个新的Task去执行await的awaitable方法,并且把执行结果返回,然后会启动一个新的Task,从原来的程序await的地方继续往下执行。通过这种方式就简单的实现了多线程,简化的复杂的创建线程,控制管理等内容。
async/await 使用注意事项
避免使用async void
Async的方法从语法上来说,可以定义的返回值有三种:Task, Task
private async void button1_Click(object sender, EventArgs e)
{
await Button1ClickAsync();
}
public async Task Button1ClickAsync()
{
// Do asynchronous work.
await Task.Delay(1000);
}
要使用async的话,就要全部都使用async. (async all the way)
这个是在实际中经常出现的问题。从上面的解释中可以理解到,由于async的方法是交由CLR去调度执行在具体的线程上的,所以你不知道哪些Task可能会被调度在同一个线程上,如果你用了同步的方法锁住了线程,就有可能造成死锁。原理明白后就是要注意具体有哪些方法其实是同步的方法了,最常见的是 .Result 和 .Wait()。下表总结了一些常见的错误:
To Do This … | Instead of This … | Use This |
---|---|---|
Retrieve the result of a background task | Task.Wait or Task.Result | await |
Wait for any task to complete | Task.WaitAny | await Task.WhenAny |
Retrieve the results of multiple tasks | Task.WaitAll | await Task.WhenAll |
Wait a period of time | Thread.Sleep | await Task.Delay |
当然全部使用async中还是有一些例外的,例外就是在Main函数中。Console Application中的Main函数是必须要使用同步方法的。建议是只在最外层使用同步方法,而在其他地方都用async。例如:
class Program
{
static void Main()
{
MainAsync().Wait();
}
static async Task MainAsync()
{
try
{
// Asynchronous implementation.
await Task.Delay(1000);
}
catch (Exception ex)
{
// Handle exceptions.
}
}
}
总结
简单总结一下,.NET提供了一种很棒的多线程编程的抽象:Task。从原理上说,就是CLR会维护一个线程池,调度程序定义的Task到线程上进行执行。async/await是.NET4.5后提供的关键词,可以很方便的定义和使用Task,但是需要注意使用async的话要一路都全部使用async,不能混合同步方法和异步方法,否则会导致死锁。 关于c#的并行编程还有很多可以深入的地方,这里只是谈了下我自己的一些浅显的认识,希望能有所帮助。如果有错误的地方,还请不吝赐教。
参考资料
- http://blog.slaks.net/2013-10-11/threads-vs-tasks/
- https://msdn.microsoft.com/en-us/magazine/jj991977.aspx