aync await 进一步探索
首先来个例子
class Program
{
static int index = 1;
static void Log(string str)
{
Console.WriteLine((index++) + ". " + str + ". ThreadId:" + Thread.CurrentThread.ManagedThreadId);
}
static void Main(string[] args)
{
//解决.net core控制台输出中文乱码的代码
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
//async 不能用于Main方法,所以在这里单独使用一个方法来调用,各位可以试试,编译不过,但VS就是不会告诉你错误在哪里
ExcuteAsync();
Console.ReadLine();
}
static async void ExcuteAsync() {
Log("异步方法调用前");
var ret = AsyncMethod();
Log("异步方法调用后");
Log(await ret);
Log("异步方法使用await后");
}
static async Task<string> AsyncMethod() {
Log("异步方法开始");
var task = Task.Run<string>(() =>
{
Log("异步方法内部开始");
Thread.Sleep(3000);
Log("异步方法内部结束");
return "来自异步方法内部的结果";
});
Log("异步方法结束");
var ret = await task;
Log("异步方法await结束");
return ret;
}
}
控制台输出结果
1. 异步方法调用前. ThreadId:1
2. 异步方法开始. ThreadId:1
3. 异步方法结束. ThreadId:1
4. 异步方法内部开始. ThreadId:3
5. 异步方法调用后. ThreadId:1
6. 异步方法内部结束. ThreadId:3
7. 异步方法await结束. ThreadId:3
8. 来自异步方法内部的结果. ThreadId:3
9. 异步方法使用await后. ThreadId:3
分析
为了描述更方便,为每条输出都添加了序号。 为了更清晰的知道每一步的执行顺序以及所在的线程,均添加了ThreadId
- 第1条输出,主线程,没有什么特别的。
- 第2条输出,主线程,说明:调用异步方法本身并不会另起一个线程,如果这里面没有await的话,调用这个方法和调用普通方法没有任何区别。
- 第3条输出,主线程,说明:执行异步方法后主线程并没有被挂起,而是直接继续往下走。
- 第4条输出,线程3(代表子线程,不一定每次都是3),代码显示的要起用一个新线程,没有什么特别的。
- 第5条输出,主线程,和第3条一样,主线程继续往下走,只是代码在不同的方法里而已。
- 第6条输出,线程3,内部执行结束,没什么特别。
- 第7条输出,线程3,说明:这里有一个不同的地方,使用了await,可见,这里是子线程的延续
- 第8-9条输出,线程3,和第7条一样,延续了子线程。
变种
我们把ExcuteAsync方法里的await ret,改成ret.Result看看效果
1. 异步方法调用前. ThreadId:1
2. 异步方法开始. ThreadId:1
3. 异步方法结束. ThreadId:1
4. 异步方法内部开始. ThreadId:3
5. 异步方法调用后. ThreadId:1
6. 异步方法内部结束. ThreadId:3
7. 异步方法await结束. ThreadId:3
8. 来自异步方法内部的结果. ThreadId:1
9. 异步方法使用await后. ThreadId:1
第8-9条输出线程变了,可见是主线程被挂起了,等待子线程结束后继续往下执行。那么如果在AsyncMethod里也使用Result,效果又是什么样的?
我们把AsyncMethod方法里的await task改成task.Result,看输出结果
1. 异步方法调用前. ThreadId:1
2. 异步方法开始. ThreadId:1
3. 异步方法结束. ThreadId:1
4. 异步方法内部开始. ThreadId:3
5. 异步方法内部结束. ThreadId:3
6. 异步方法await结束. ThreadId:1
7. 异步方法调用后. ThreadId:1
8. 来自异步方法内部的结果. ThreadId:1
9. 异步方法使用await后. ThreadId:1
现在只有Task内部的输出是在子线程了。可见,使用Result的话会失去异步的效果,换句话说,使用Result就不再是异步调用了。
附:文笔不好,只能用习惯的代码来描述,希望能给读者带来帮助。
?
时间: 2024-10-14 15:35:11