2

いくつかの同期プログラムに並行性を追加する方法を学び、フィボナッチ アルゴリズムを例として取り上げます。これらのコードを書きましたが、同時実行性がまったくないことがわかりました。すべてのコードは、完了するまで単一のスレッドで実行されます。非同期が反映されない理由を誰かに説明してもらえますか?

    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 を作成しようとしましたが、うまくいきました。しかし、非同期関数が Task タイプの値を返すことに気付きました。これは Task.Run() と同じです。どちらのタスクもすぐに実行されますが、t1は新しいスレッドで自動的に実行されません。これら2つのタスクの違いは何ですか?非同期関数を新しいスレッドで自動的に実行できますか?

    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(); });
    }
4

4 に答える 4

5

まず、.NET 4.5 の async/await モデルに実験的な CTP を使用しています。このような環境では、物事がぎこちなく振る舞うことを予期する必要があります。

第二に、最後に無期限に眠っていることを認識していますか?

第 3 に、アプリケーションは本質的に同期的です。非同期タスクを作成し、その後すぐに待機します。async/await モデルは同時実行性を追加せず、非同期のみを追加します。複数のことを実行しながら、アプリケーションが応答できるようにするだけです。自動的に並列化されません。これが、アプリケーションが同期しているかのように動作する理由です。

于 2012-04-20T12:10:07.710 に答える
2

この動作には 2 つの理由があります。

まず、非同期メソッドは、await ステートメントを評価する必要があるまで同期的に実行されます。待機する前に再帰しているため、何も待機する前にすべての再帰が同期的に終了します。

第 2 に、待機中のタスクが既に完了している場合、それらの待機中のタスクは同期的に実行される可能性があります。あなたのコードは、まだ完了していないタスクを決して作成しません。同期的にラップしてタスクに 0 または 1 を返すか、同期的に完了した 2 つのタスクを同期的に追加してその結果を返します。

どこかに非同期の側面を導入する必要があります。例えば:

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);
    }
}
于 2012-04-20T12:50:50.887 に答える
0

スレッドプールでタスクをまったく開始していません。デフォルトでは、await は並列処理を導入しません。

次のように変更します。

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

これは可能な限り効率的ではありませんが、開始するには役立ちます。

于 2012-04-20T12:35:11.830 に答える
0
    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];
                }
            }
            );
    }
于 2013-12-18T13:03:37.453 に答える