1

非常に大規模な既存の同期コード ベースで async/await を使用しようとしています。このコード ベースには、同期コンテキストでは問題なく動作するグローバルな状態がいくつかありますが、async/await の非同期コンテキストでは動作しません。

したがって、私の 2 つのオプションは、非常に大規模で非常に時間のかかる作業になるグローバル コンテキストを除外するか、継続が実行されるときに何か賢いことを行うことです。

async/await と継続をよりよく理解するために、ここに示すテスト プログラムを作成しました。ここに示されています。

    // A method to simulate an Async read of the database.
    private static Task ReadAsync()
    {
        return Task.Factory.StartNew(() =>
        {
            int max = int.MaxValue / 2;
            for (int i = 0; i < max; ++i)
            {
            }
        });
    }

    // An async method that creates several continuations.
    private static async Task ProcessMany(int i)
    {
        Console.WriteLine(string.Format("{0} {1}", i.ToString(), 0));

        await ReadAsync();

        Console.WriteLine(string.Format("{0} {1}", i.ToString(), 1));

        await ReadAsync();

        Console.WriteLine(string.Format("{0} {1}", i.ToString(), 2));

        await ReadAsync();

        Console.WriteLine(string.Format("{0} {1}", i.ToString(), 3));
    }


    public static void Main(string[] args)
    {
        Queue<Task> queue = new Queue<Task>();

        for (int i = 0; i < 10; ++i)
        {
            queue.Enqueue(ProcessMany(i));
        }

        // Do some synchonous processing...
        Console.WriteLine("Processing... ");

        for (int i = 0; i < int.MaxValue; ++i)
        {
        }

        Console.WriteLine("Done processing... ");

        queue.Dequeue().Wait();
    }

async/await についてすべて読んだ後、私の理解では、"Processing.." と "Done processing..." WriteLines の間で継続は発生しないということです。

出力例を次に示します。

0 0
1 0
2 0
3 0
4 0
5 0
6 0
7 0
8 0
9 0
Processing...
3 1
2 1
7 1
6 1
0 1
4 1
5 1
1 1
6 2
3 2
Done processing...
7 2
2 2
0 2
4 2
5 2
1 2
6 3
3 3
7 3
2 3
0 3

プログラムの最後にある単一の Wait() が、最初の継続が終了するまでに複数の継続につながる可能性があると予想しますが、「処理中...」と「処理完了」の間で継続がどのように実行されるかわかりません... "。Console.WriteLine メソッドにyieldか何かがあるのではないかと思い、丸ごと差し替えましたが、出力は変わりませんでした。

async/await についての私の理解には明らかにギャップがあります。単純に変数をインクリメントしているとき、どのようにして継続が発生するのでしょうか? コンパイラまたは CLR は、ここにある種の魔法を注入していますか?

async/await と継続をよりよく理解するための助けを前もって感謝します。

編集:

Stephen のコメントに従ってサンプル コードをこのように編集すると、何が起こっているのかがより明確になります。

    // An async method that creates several continuations.
    private static async Task ProcessMany(int i)
    {
        Console.WriteLine(string.Format("{0} {1} {2}", i.ToString(), 0, Thread.CurrentThread.ManagedThreadId));

        await ReadAsync();

        Console.WriteLine(string.Format("{0} {1} {2}", i.ToString(), 1, Thread.CurrentThread.ManagedThreadId));

        await ReadAsync();

        Console.WriteLine(string.Format("{0} {1} {2}", i.ToString(), 2, Thread.CurrentThread.ManagedThreadId));

        await ReadAsync();

        Console.WriteLine(string.Format("{0} {1} {2}", i.ToString(), 3, Thread.CurrentThread.ManagedThreadId));
    }


    public static void Main(string[] args)
    {
        Queue<Task> queue = new Queue<Task>();

        for (int i = 0; i < 10; ++i)
        {
            queue.Enqueue(ProcessMany(i));
        }

        // Do some synchonous processing...
        Console.WriteLine("Processing... {0}", Thread.CurrentThread.ManagedThreadId);

        for (int i = 0; i < int.MaxValue; ++i)
        {
        }

        Console.WriteLine("Done processing... {0}", Thread.CurrentThread.ManagedThreadId);

        queue.Dequeue().Wait();
    }

出力:

0 0 9
1 0 9
2 0 9
3 0 9
4 0 9
5 0 9
6 0 9
7 0 9
8 0 9
9 0 9
Processing... 9
4 1 14
3 1 13
2 1 12
5 1 15
0 1 10
6 1 16
1 1 11
7 1 17
4 2 14
3 2 13
0 2 10
6 2 16
2 2 12
5 2 15
Done processing... 9
1 2 11
7 2 17
0 3 10
4 3 14
4

2 に答える 2

5

SynchronizationContext現在のまたはがない場合TaskScheduler、継続は (メイン スレッドとは別に) スレッド プール スレッドで実行されます。これはコンソール アプリの場合ですが、WinForms/WPF/ASP.NET では非常に異なる動作が見られます。

custom を使用して継続スケジュールを制御することはできますがTaskScheduler、それはかなりの作業であり、おそらくメリットはほとんどありません。あなたのグローバルな状態にどのような問題があるのか​​ はわかりませんが、次のような代替案を検討してくださいSemaphoreSlim

于 2013-05-29T18:59:44.517 に答える