【问题标题】:How to use async methods如何使用异步方法
【发布时间】:2020-03-20 09:59:29
【问题描述】:

我目前在正确使用异步方法时遇到问题。我可能误会了什么...

在我当前的项目中,我有一些应该并行运行的异步方法,但它们没有。所以我创建了一个小示例项目来重现错误。

class Program
    {
        static void Main(string[] args)
        {
            TaskAwaiter taskAwaiter = SomeParallelWork().GetAwaiter();
            taskAwaiter.GetResult();
        }

        private static async Task SomeParallelWork()
        {
            Console.WriteLine(DateTime.Now + ": Start Parallel Work");
            Task<string> task1 = HeavyDBWork(6000);
            Task<string> task2 = HeavyDBWork(3000);
            Task<string> task3 = HeavyDBWork(5000);
            Console.WriteLine(DateTime.Now + ": All Parallel Work started");
            await Task.WhenAll(new Task<string>[] { task1, task2, task3 });
            Console.WriteLine(DateTime.Now + ": All Parallel Work done");
        }


        private static async Task<string> HeavyDBWork(int timeToWork)
        {
            Console.WriteLine(DateTime.Now + ": Start with heavy db work load: " + timeToWork);
            await Task.Delay(timeToWork);
            Console.WriteLine(DateTime.Now + ": End of heavy db work load: " + timeToWork);
            return "SomeReturnValue";
        }
    }

输出如我所料:

20.03.2020 10:50:28: Start Parallel Work
20.03.2020 10:50:28: Start with heavy db work load: 6000
20.03.2020 10:50:28: Start with heavy db work load: 3000
20.03.2020 10:50:28: Start with heavy db work load: 5000
20.03.2020 10:50:28: All Parallel Work started
20.03.2020 10:50:31: End of heavy db work load: 3000
20.03.2020 10:50:33: End of heavy db work load: 5000
20.03.2020 10:50:34: End of heavy db work load: 6000
20.03.2020 10:50:34: All Parallel Work done

首先生成所有任务,然后并行运行。 但这不是我在项目中所经历的......

所以我用一些更“真实”的工作扩展了我的示例:递归斐波那契算法

class Program
    {
        static void Main(string[] args)
        {
            TaskAwaiter taskAwaiter = SomeParallelWork().GetAwaiter();
            taskAwaiter.GetResult();
        }

        private static async Task SomeParallelWork()
        {
            Console.WriteLine(DateTime.Now + ": Start Parallel Work");
            Task<long> fibuTask = CPUWork(40);
            Task<string> task1 = HeavyDBWork(6000);
            Task<string> task2 = HeavyDBWork(3000);
            Task<string> task3 = HeavyDBWork(5000);
            Console.WriteLine(DateTime.Now + ": All Parallel Work started");
            await Task.WhenAll(new Task<string>[] { task1, task2, task3 });
            await Task.WhenAll(new Task<long>[] { fibuTask });
            Console.WriteLine(DateTime.Now + ": All Parallel Work done");
        }


        private static async Task<string> HeavyDBWork(int timeToWork)
        {
            Console.WriteLine(DateTime.Now + ": Start with heavy db work load: " + timeToWork);
            await Task.Delay(timeToWork);
            Console.WriteLine(DateTime.Now + ": End of heavy db work load: " + timeToWork);
            return "SomeReturnValue";
        }

        private static async Task<long> CPUWork(int i)
        {
            Console.WriteLine(DateTime.Now + ": Start Fibu of " + i);
            long fibu = Fibu(i);
            Console.WriteLine(DateTime.Now + ": End Fibu of " + i);
            return await Task.FromResult<long>(fibu);
        }


        private static long Fibu(int i)
        {
            if(i==1||i==2)
            {
                return (long)1;
            } else
            {
                return Fibu(i-2) + Fibu(i - 1);
            }
        }
    }

输出:

20.03.2020 10:56:09: Start Parallel Work
20.03.2020 10:56:09: Start Fibu of 40
20.03.2020 10:56:10: End Fibu of 40
20.03.2020 10:56:10: Start with heavy db work load: 6000
20.03.2020 10:56:10: Start with heavy db work load: 3000
20.03.2020 10:56:10: Start with heavy db work load: 5000
20.03.2020 10:56:10: All Parallel Work started
20.03.2020 10:56:13: End of heavy db work load: 3000
20.03.2020 10:56:15: End of heavy db work load: 5000
20.03.2020 10:56:16: End of heavy db work load: 6000
20.03.2020 10:56:16: All Parallel Work done

现在 Fibunacci Sequence 任务不仅仅是首先创建的,它是在创建其他任务之前等待的方式。 我希望代码能够创建所有任务并并行运行它们。我做错了什么?

感谢您的回答!

答案:

感谢 Johnathan、Lasse 和 Theodor,我能够修复我的代码示例。

所以新示例异步执行三个斐波那契算法。

class Program
    {
        static void Main(string[] args)
        {
            TaskAwaiter taskAwaiter = SomeParallelWork().GetAwaiter();
            taskAwaiter.GetResult();
        }

        private static async Task SomeParallelWork()
        {
            Console.WriteLine(DateTime.Now + ": Start Parallel Work");
            Task<long> fibuTask1 = CPUWork(45);
            Task<long> fibuTask2 = CPUWork(40);
            Task<long> fibuTask3 = CPUWork(40);
            Console.WriteLine(DateTime.Now + ": All Parallel Work started");

            //await Task.WhenAll(new Task<string>[] { task1, task2, task3 });
            await Task.WhenAll(new Task<long>[] { fibuTask1, fibuTask2, fibuTask3 });
            Console.WriteLine(DateTime.Now + ": All Parallel Work done");
        }


        private static async Task<string> HeavyDBWork(int timeToWork)
        {
            Console.WriteLine(DateTime.Now + ": Start with heavy db work load: " + timeToWork);

            await Task.Delay(timeToWork);
            Console.WriteLine(DateTime.Now + ": End of heavy db work load: " + timeToWork);
            return "SomeReturnValue";
        }

        private static async Task<long> CPUWork(int i)
        {
            Console.WriteLine(DateTime.Now + ": Start Fibu of " + i);

            Func<long> fibuFunc = () => Fibu(i);
            Task<long> fibuTask = Task.Run(fibuFunc);

            long fibu = await fibuTask;


            Console.WriteLine(DateTime.Now + ": End Fibu of " + i);
            return fibu;
        }


        private static long Fibu(int i)
        {
            if(i==1||i==2)
            {
                return (long)1;
            } else
            {
                return Fibu(i-2) + Fibu(i - 1);
            }
        }
    }

输出:

20.03.2020 11:59:39: Start Parallel Work
20.03.2020 11:59:39: Start Fibu of 45
20.03.2020 11:59:39: Start Fibu of 40
20.03.2020 11:59:39: Start Fibu of 40
20.03.2020 11:59:39: All Parallel Work started
20.03.2020 11:59:41: End Fibu of 40
20.03.2020 11:59:41: End Fibu of 40
20.03.2020 11:59:53: End Fibu of 45
20.03.2020 11:59:53: All Parallel Work done

【问题讨论】:

  • 添加async 关键字并不会神奇地将其变成后台任务或单独的线程,您仍然需要实际上执行一些异步操作。在您的情况下,整个方法及其调用的所有内容仍然是 100% 同步代码,因此它将在返回任务之前运行完成。您可以使用Task.Run(搜索 SO 以获取示例)创建将使用线程池运行的任务。
  • 您可以通过将return await Task.FromResult&lt;long&gt;(fibu) 替换为return fibu 来简化它。
  • 你应该阅读关于异步/等待和状态机devblogs.microsoft.com/premier-developer/…

标签: c# asynchronous parallel-processing async-await


【解决方案1】:

您的CPUWork 方法实际上将同步运行,即使它被声明为async

异步方法只在遇到第一个await 时返回Task,而Task.FromResult 只是将一个值包装在一个已经完成的Task 中,因此使用await 只会立即解开该值并返回它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-03-06
    • 2021-10-24
    • 1970-01-01
    • 1970-01-01
    • 2016-07-20
    • 2013-12-25
    相关资源
    最近更新 更多