1 引言
官方文档:https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/concepts/async
看微软的官方文档看的头大,比较晦涩的,反正我是啃不动,这里通俗的解释一下c# 中的await/async
2 await/async是什么
说白了await/async就是一个语法糖,单纯使用await/async并不会创建一个线程,创建线程的这个操作由是线程池决定的。
那么我们为啥还要使用await/async呢?
答:为了更好的编写异步操作,也就是识别性更高
3 错误的调用异步方法
3.1 方法上只添加async,但内部未使用Task.Run
可以看到,单纯在方法上添加async,是不会执行异步的。
想要异步,还需要在方法内部使用Task.Run或者创建线程。
3.2 方法内部未处理返回值
可以看到,CalculateSum方法内部的Task.Run,并没有阻塞,也就是我们并没得到异步线程计算后c的值。
如果我们在方法上加async呢?结果是一致的。
4 使用await等待Task.Run的结果
我们在原有的Task.Run前面加await,发现报错
所以我们需要这么做,在CalculateSum方法上添加async关键词,这时候又报错了。
因为我们是有返回值的,异步方法的返回值只能是void,Task,或者Task< T >,我们添加返回值Task< int >
5 如何调用我们写的异步方法
经过上面的错误操作后,这时我们的异步方法已经写好了,如下
Console.WriteLine("start");
CalculateSum(1, 2);
CalculateSum(1, 2);
CalculateSum(1, 2);
CalculateSum(1, 2);
Console.WriteLine("end");
Console.ReadKey();
public static class MThread
{
public static async Task<int> CalculateSum(int a, int b)
{
int c = 0;
await Task.Run(() =>
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId+":start");
Thread.Sleep(1000 * 3);
Console.WriteLine(Thread.CurrentThread.ManagedThreadId+":end");
c= a + b;
});
Console.WriteLine("计算结果:"+c);
return c;
}
}
运行结果:
我们发现,实现的异步的效果,主线程没有被阻塞。
那么又有问题了,我们的异步方法是有返回值的,主线程没有被阻塞我们如何得到返回值呢,接着往下看。
6 得到异步方法的返回值。
6.1 通过Task.Result阻塞获得返回值
代码:
Console.WriteLine("start");
Task<int> task = CalculateSum(1, 2);
Task<int> task2 = CalculateSum(1, 2);
Task<int> task3 = CalculateSum(1, 2);
Task<int> task4 = CalculateSum(1, 2);
Console.WriteLine("end");
Console.WriteLine("开始等待返回结果");
Console.WriteLine(task.Result);
Console.WriteLine(task2.Result);
Console.WriteLine(task3.Result);
Console.WriteLine(task4.Result);
Console.WriteLine("等待返回结果完毕,程序结束");
public static class MThread
{
public static async Task<int> CalculateSum(int a, int b)
{
int c = 0;
await Task.Run(() =>
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId+":start");
Thread.Sleep(1000 * 3);
Console.WriteLine(Thread.CurrentThread.ManagedThreadId+":end");
c= a + b;
});
Console.WriteLine("计算结果:"+c);
return c;
}
}
结果:
结论:
主线程没有阻塞,但是调用task.Result时会阻塞,直到该线程返回结果后,阻塞结束
6.2 通过await等待返回值
代码:
Console.WriteLine("start");
int res = await CalculateSum(1, 2);
int res2 = await CalculateSum(1, 2);
int res3 = await CalculateSum(1, 2);
int res4 = await CalculateSum(1, 2);
Console.WriteLine(res);
Console.WriteLine(res2);
Console.WriteLine(res3);
Console.WriteLine(res4);
Console.WriteLine("end");
Console.WriteLine("等待返回结果完毕,程序结束");
public static class MThread
{
public static async Task<int> CalculateSum(int a, int b)
{
int c = 0;
await Task.Run(() =>
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId+":start");
Thread.Sleep(1000 * 3);
Console.WriteLine(Thread.CurrentThread.ManagedThreadId+":end");
c= a + b;
});
Console.WriteLine("计算结果:"+c);
return c;
}
}
结果:
结论:
主线程被await阻塞,直到该线程返回结果后,才向下执行。
7 总结
编写异步方法
-
编写异步方法时,需要标识
async
关键词。 -
编写异步方法时,返回值只能是
void,Task,Task<T>
。 -
如果返回值是Task。方法体无需有返回值,直接
await Task.Run(() =>{});
即可 -
想要异步,必须在方法内部开启新的线程。并且需要
await Task.Run(() =>{});
使用异步方法
想要得到异步方法返回值,就需要阻塞,调用await
或者T.Result
来阻塞异步方法,得到返回值。
异步方法模板
Console.WriteLine("start");
await CalculateSum(1, 2);
Task calculateSum2 = CalculateSum2(1, 2);
CalculateSum3(1, 2);
CalculateSum4(()=>
{
Console.WriteLine("这是一个异步操作");
});
Console.WriteLine("end");
Console.ReadKey();
public static class MThread
{
public static async Task<int> CalculateSum(int a, int b)
{
int c = 0;
await Task.Run(() =>
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":start");
Thread.Sleep(1000 * 3);
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":end");
c = a + b;
});
Console.WriteLine("计算结果:" + c);
return c;
}
public static async Task CalculateSum2(int a, int b)
{
int c = 0;
await Task.Run(() =>
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":start");
Thread.Sleep(1000 * 3);
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":end");
c = a + b;
});
Console.WriteLine(c);
}
public static async void CalculateSum3(int a, int b)
{
int c = 0;
await Task.Run(() =>
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":start");
Thread.Sleep(1000 * 3);
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":end");
c = a + b;
});
Console.WriteLine(c);
}
public static async Task CalculateSum4(Action action)
{
await Task.Run(action);
}
}