【问题标题】:How to add concurrency to synchronous program by C# async/await如何通过 C# async/await 为同步程序添加并发性
【发布时间】:2012-05-02 00:29:39
【问题描述】:

我想学习如何在一些同步程序中添加并发,并以斐波那契算法为例。我写了这些代码,但我发现它根本没有任何并发​​性。所有代码都在单个线程中运行,直到完成。谁能向我解释为什么它不反映异步?

    async static Task<int> Fibonacci(int n)
    {
        if (n == 0) { return 0; }
        else if (n == 1) { return 1; }
        else
        {
            var t1 = Fibonacci(n - 1);
            var t2 = Fibonacci(n - 2);
            return (await t1) + (await t2);
        }
    }

    static int Main(string[] args)
    {
        var fib = Fibonacci(25);
        fib.Wait();
        Console.WriteLine( fib.Result );
        Console.ReadKey();
        return 0;
    }

在 Michael 的提示下,我尝试在 async 函数中创建任务,它可以工作。 但我注意到异步函数返回一个任务类型值,它与 Task.Run() 相同。这两个任务都会立即运行,但 t1 不会自动运行到新线程中。 谁能告诉我,这两个任务有什么不同。我可以让异步函数自动运行到新线程吗?

    async static Task<string> Async1()
    {
        return DateTime.Now.ToString();
    }
    static void Main(string[] args)
    {
        Task<string> t1 = Async1();
        Task<string> t2 = Task.Run<string>(() => { return DateTime.Now.ToString(); });
    }

【问题讨论】:

  • 没有反应是什么意思?运行程序时会发生什么?
  • 你希望它有什么反应?
  • 我希望你知道这是一个非常低效的算法(提示:计算 fib(20) 的计算频率)?好的,可以测试异步工作(需要很长时间:-))。
  • 这个算法的阶数不好(O(2^N))。对于多项式顺序,您可以使用动态规划或计算斐波那契矩阵...您需要更多帮助吗?
  • 我只是以斐波那契算法为例。我知道它可能不适合改为多线程。

标签: c# multithreading asynchronous concurrency async-await


【解决方案1】:
    private async Task<int> ComputeFibAsync(int n)
    {
        return await Task.Run(
            async () =>
            {
                if (n < 2)
                {
                    return 1;
                }
                else
                {
                    var result = await Task.WhenAll<int>(ComputeFibAsync(n - 1), ComputeFibAsync(n - 2));
                    return result[0] + result[1];
                }
            }
            );
    }

【讨论】:

    【解决方案2】:

    这种行为有两个原因。

    首先,异步方法同步运行,直到它们必须评估等待语句。您在等待之前进行递归,因此所有递归都将在等待任何内容之前同步完成。

    其次,如果等待的任务已经完成,那么它们的等待可能会同步运行。您的代码永远不会创建尚未完成的任务。它要么在一个任务中同步包装并返回 0 或 1,要么同步添加两个同步完成的任务并返回该结果。

    您需要在某处引入非同步方面。例如:

    async static Task<int> Fibonacci(int n)
    {
        if (n == 0) { return 0; }
        else if (n == 1) { return 1; }
        else
        {
            // run one of the recursions concurrently
            var t1 = Task.Factory.StartNew(() => Fibonacci(n - 1));
            var t2 = Fibonacci(n - 2);
            return (await (await t1)) + (await t2);
        }
    }
    

    【讨论】:

      【解决方案3】:

      您根本没有在线程池上启动任务。 await 默认情况下不引入并行性。

      改成:

              var t1 = Task.Factory.StartNew(() => Fibonacci(n - 1)).Unwrap();
              var t2 = Task.Factory.StartNew(() => Fibonacci(n - 2)).Unwrap();
      

      这并不像它所能达到的那样有效,但它会让你开始。

      【讨论】:

        【解决方案4】:

        首先,您正在为 .NET 4.5 的 async/await 模型使用实验性 CTP。在这样的环境中,你应该预料到事情会表现得很尴尬。

        第二,你知道你最后会无限期地睡觉吗?

        第三,您的应用程序本质上是同步的。您创建一个异步任务,然后立即等待它。 async/await 模型不添加并发,只添加异步。它只是让您的应用程序在执行多项操作时具有响应性;它不会自动并行化。这就是为什么您的应用程序表现得好像是同步的。

        【讨论】:

          猜你喜欢
          • 2020-03-06
          • 2017-05-07
          • 1970-01-01
          • 2017-09-17
          • 1970-01-01
          • 2019-10-31
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多