joe 发表于 2022-6-8 17:12:36

async/await异步执行

public static string DateTime_Now_ToString()
      {
            return DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff");
      }
      public static string procstr(string arg)
      {
            Thread.Sleep(4000);
            return arg + "test";
      }
      private static async Task<string> GetAwaitString(string str)
      {
            /*
                async Task<string> GetAwaitRunString(string str) 方法内部是同步执行的。
                直到运行到 await 关键字(内部)是异步执行的(使用后台线程池)。
             */
            Console.WriteLine("GetAwaitString await前:\t线程Id:【{0}】\t后台线程:【{1}】\t使用线程池:【{2}】\t当前时间:【{3}】",
                Environment.CurrentManagedThreadId.ToString(),
                Thread.CurrentThread.IsBackground,
                Thread.CurrentThread.IsThreadPoolThread,
                DateTime_Now_ToString());

            var task = await System.Threading.Tasks.Task.Run<string>(() =>
            {
                Thread.Sleep(5000);
                Console.WriteLine("GetAwaitString await后:\t线程Id:【{0}】\t后台线程:【{1}】\t使用线程池:【{2}】\t当前时间:【{3}】",
                Environment.CurrentManagedThreadId.ToString(),
                Thread.CurrentThread.IsBackground,
                Thread.CurrentThread.IsThreadPoolThread,
                DateTime_Now_ToString());
                return str + "," + DateTime_Now_ToString();
            });

            Console.WriteLine("before return" + Environment.CurrentManagedThreadId);//这一句看起来不能执行,其实,只能是btn的click事件处理完之后才会再次进到此以主线程身份执行
            var task2 = await System.Threading.Tasks.Task.Run<string>(() =>
            {
                return procstr(task);
            });
            Console.WriteLine("task2=" + task2);
            return task;
      }
private void btnNAstart_Click(object sender, EventArgs e)
      {
            Console.WriteLine("主线程:\t\t\t线程Id:【{0}】\t后台线程:【{1}】\t使用线程池:【{2}】\t当前时间:【{3}】",
                Environment.CurrentManagedThreadId,
                Thread.CurrentThread.IsBackground,
                Thread.CurrentThread.IsThreadPoolThread,
                DateTime_Now_ToString());
            var rlt =GetAwaitString("abcd123");
            Console.WriteLine("结果:" + rlt); //无意义的值
            //Console.WriteLine("结果:" + rlt.Result); //rlt.Result则就一定会阻塞
         //也就是说,如果本btn click事件代码是另一个线程或task中代码,那么可以用rlt.Result待方式取得异步执行的值
            Console.WriteLine("执行完毕:" + DateTime_Now_ToString());
       }


joe 发表于 2022-6-9 09:28:39

有一个要点:Task.Result会直接阻塞当前调用线程,而aysnc、await机制是使用状态机切换上下文

joe 发表于 2022-6-9 13:53:08

关于Task的异常:
与Thread不一样,Task可以很方便的传播异常 如果你的task里面抛出了一个未处理的异常,那么该异常就会重新被抛出给:

调用了wait()的地方
访问了Task的Reuslt属性的地方。

joe 发表于 2022-6-9 13:56:07

还有一个网页可参考:c#异步编程-Task(一) https://zhuanlan.zhihu.com/p/310646064
页: [1]
查看完整版本: async/await异步执行