首页 > 代码库 > aync await 进一步探索

aync await 进一步探索

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:12. 异步方法开始. ThreadId:13. 异步方法结束. ThreadId:14. 异步方法内部开始. ThreadId:35. 异步方法调用后. ThreadId:16. 异步方法内部结束. ThreadId:37. 异步方法await结束. ThreadId:38. 来自异步方法内部的结果. ThreadId:39. 异步方法使用await后. ThreadId:3

分析

为了描述更方便,为每条输出都添加了序号。 为了更清晰的知道每一步的执行顺序以及所在的线程,均添加了ThreadId

  1. 第1条输出,主线程,没有什么特别的。
  2. 第2条输出,主线程,说明:调用异步方法本身并不会另起一个线程,如果这里面没有await的话,调用这个方法和调用普通方法没有任何区别。
  3. 第3条输出,主线程,说明:执行异步方法后主线程并没有被挂起,而是直接继续往下走。
  4. 第4条输出,线程3(代表子线程,不一定每次都是3),代码显示的要起用一个新线程,没有什么特别的。
  5. 第5条输出,主线程,和第3条一样,主线程继续往下走,只是代码在不同的方法里而已。
  6. 第6条输出,线程3,内部执行结束,没什么特别。
  7. 第7条输出,线程3,说明:这里有一个不同的地方,使用了await,可见,这里是子线程的延续
  8. 第8-9条输出,线程3,和第7条一样,延续了子线程。

变种

我们把ExcuteAsync方法里的await ret,改成ret.Result看看效果

1. 异步方法调用前. ThreadId:12. 异步方法开始. ThreadId:13. 异步方法结束. ThreadId:14. 异步方法内部开始. ThreadId:35. 异步方法调用后. ThreadId:16. 异步方法内部结束. ThreadId:37. 异步方法await结束. ThreadId:38. 来自异步方法内部的结果. ThreadId:19. 异步方法使用await后. ThreadId:1

第8-9条输出线程变了,可见是主线程被挂起了,等待子线程结束后继续往下执行。那么如果在AsyncMethod里也使用Result,效果又是什么样的?

我们把AsyncMethod方法里的await task改成task.Result,看输出结果

1. 异步方法调用前. ThreadId:12. 异步方法开始. ThreadId:13. 异步方法结束. ThreadId:14. 异步方法内部开始. ThreadId:35. 异步方法内部结束. ThreadId:36. 异步方法await结束. ThreadId:17. 异步方法调用后. ThreadId:18. 来自异步方法内部的结果. ThreadId:19. 异步方法使用await后. ThreadId:1

现在只有Task内部的输出是在子线程了。可见,使用Result的话会失去异步的效果,换句话说,使用Result就不再是异步调用了

 

附:文笔不好,只能用习惯的代码来描述,希望能给读者带来帮助。

?

aync await 进一步探索