async\await用法


private void button1_Click(object sender, EventArgs e)
        {
            Task<int> task = Fun3();
            Task task2 = Func1();
            Console.WriteLine("等待前输出");
            await task;
            await task2;
            //Task.WaitAll(task, task2); //这种写法会阻塞主线程,导致死锁
            Console.WriteLine("等待后输出");
            Console.WriteLine(task.Result);
        }

        private static async Task Func1()
        {
            await Task.Run(() =>
            {
                Thread.Sleep(2000);
                Console.WriteLine("2222");
            });
        }

        private static async Task<int> Fun3()
        {
            int ret = 0;
            await Task.Run(() =>
            {

                var result = Task.Run(async () => await Fun4());
                if (result.Result > 0)
                {
                    Console.WriteLine("正确流程");

                }
                else
                {
                    Console.WriteLine("错误流程");
                    ret = 1;
                }
            });
            return ret;
        }

        private static async Task<int> Fun4()
        {
            int ret = 0;
            await Task.Run(() =>
            {
                if (3 > 2)
                    ret = 1;
            });
            return ret;
        }

Fun1和Func3是2个单独的任务,可以异步执行。Fun3执行时需依赖Fun4的结果,才能执行后续。上边的写法看起来功能可以实现,不过感觉写法有点奇怪,之前用的比较少,请熟悉的人帮忙看下。如果写法有问题,需要怎么修改?

该回答引用GPTᴼᴾᴱᴺᴬᴵ
这段代码的使用 async 和 await 是正确的,可以实现异步执行任务的效果。不过有几点需要注意:

1.Func1 方法的实现没有必要使用 Task.Run,因为 Task.Run 会把代码放到线程池中执行,而 Thread.Sleep 不会占用线程。所以可以直接写成:

private static async Task Func1()
{
    await Task.Delay(2000);
    Console.WriteLine("2222");
}


2.Fun3 方法中有一个奇怪的写法:

var result = Task.Run(async () => await Fun4());
if (result.Result > 0)


这里使用 Task.Run 创建了一个新的 Task,并等待其执行完毕,这里的 Task 实际上就是 Fun4 方法的返回值。但是这里使用了 result.Result,这意味着要等待这个 Task 执行完毕并且返回结果才能继续执行后面的代码。这种写法有可能会导致死锁,因为在 UI 线程中等待一个需要执行的任务完成时,如果这个任务需要在 UI 线程中执行,那么就会导致死锁。

所以,正确的写法应该是:

int result = await Fun4();
if (result > 0)


直接使用 await 等待 Fun4 方法的返回值即可,不需要创建额外的 Task。

3.await 后面的任务有可能会抛出异常,需要使用 try-catch 捕获并处理异常。

Fun3 里直接写 await Fun4 即可

请理解await/async的含义,这个叫异步IO,不是啥某园子争论几个月都争论不清的啥子task,线程

异步IO和Task本身根本就不在一个讨论级别。不是要await 就要搞个task.run

所以你在Fun3里直接写await Fun4,不需要在Fun3里用个Task.run在套

另外提醒一下:
到底啥叫异步IO,异步IO本质上于task,线程没有必然联系
异步IO本质上的核心逻辑是异步获取执行结果,其实他是回调。只不过官方用个语法糖级别的玩意把写法简化了。
以前有也有ASynCall的写法,也有异步invoke的写法,只是代码复杂推广很多年也没有啥程序员玩熟了(而且回调还有回调地狱,代码逻辑乱)
现在这个await/async和以前的AsyncCall回调委托没有本质区别,只是语法糖罢了。(语法糖的含义就是本质上他没区别,就算用以前的代码也一样实现,不过是糖好吃)
所以回到以前的逻辑,你就知道你的Fun3其实不需要在套Task.run
回到以前的逻辑,假设你调用一个Fun4,至于Fun4开不开线程是Fun4的事情,他跟Fun3没有关系
如果fun4执行完毕,他执行一个AsyncCall回调Fun3,所以你看到了Fun3开不开Task.Run并不是重点,重点是他是一个异步IO

你套了太多层了
既然f4必须执行完才能执行f3,那你f4和f3顺序执行就好了,为什么要异步
你这异步完又同步,不够折腾的
最外层调用这几个函数的地方为了避免阻塞写个异步就行了,不要每个函数都异步

你这写的挺乱的,看你需求就是按下button时候不阻塞主线程就行了。一个async足矣

        private async void button1_Click(object sender, EventArgs e) {
            Console.WriteLine("等待前输出");
            var task = Fun3();//异步
            Func1();//异步
            Console.WriteLine("等待后输出");
            //.Result等待Fun3执行完成,还是会阻塞主线程。
            //用了.Result就别想着异步了,建议把button也改成async,就不会阻塞主线程
            //Console.WriteLine(task.Result);
            await Task.Run(()=> Console.WriteLine(task.Result));
        }

        private static async Task Func1() {
            await Task.Run(() => {
                Thread.Sleep(2000);
                Console.WriteLine("2222");
            });
        }

        private static async Task<int> Fun3() {
            int ret = 0;
            await Task.Run(() => {

                var result = Fun4();//Fun4没有异步的必要就别写成async了
                if (result > 0) {
                    Console.WriteLine("正确流程");
                } else {
                    Console.WriteLine("错误流程");
                    ret = 1;
                }
            });
            return ret;
        }

        private static int Fun4() {
            int ret = 0;
            if (3 > 2)
                ret = 1;
            return ret;
        }