Правильно ли я получил TaskCreationOptions.RunContinuationsAsynchronically? Видимо нет ... Почему? - PullRequest
1 голос
/ 11 апреля 2020

Исходя из Task.Run не выполняется и после прочтения TaskContinuationOptions.RunContinuationsAsynchronously и Stack Dives , я хотел подтвердить, что получил это право:

При использовании для TaskCompletionSource:

  • Если установлено TaskCreationOptions.RunContinuationsAsynchronously , TaskCompletionSource.SetResult() отправит все продолжения в пул потоков, где они будут ставятся в очередь и обрабатываются, может быть, похоже на их упаковку в вызовы Task.Run(). Продолжения будут обрабатываться асинхронно, в параллельных потоках пула потоков, не блокируя текущий поток / задачу.

  • Если TaskCreationOptions.RunContinuationsAsynchronously установлено , а не установлено (по умолчанию, Я предполагаю), тогда все продолжения (= делегаты в вызовах Task.ContinueWith()) выполняются синхронно, один за другим в потоке, который вызвал TaskCompletionSource.SetResult(), блокируя текущий поток / задачу до тех пор, пока все продолжения не будут обработаны, возможно, аналогично как обрабатываются делегаты событий.

Я написал следующий тест, чтобы попытаться подтвердить эти предположения:

    [TestMethod]
    public void TestTaskCreationOptions()
    {
        void callback(int i, int sleep)
        {
            Console.WriteLine($"{i} {System.Threading.Thread.CurrentThread.Description()} - before sleep {sleep}");
            System.Threading.Thread.Sleep(sleep);
            Console.WriteLine($"{i} {System.Threading.Thread.CurrentThread.Description()} - after sleep {sleep}");
        }

        void test(TaskCompletionSource<object> tcs)
        {
            Console.WriteLine($"starting: {tcs.Task.CreationOptions}");
            tcs.Task.ContinueWith((t) => callback(1,1000));
            tcs.Task.ContinueWith((t) => callback(2,300));
            tcs.Task.ContinueWith((t) => callback(3,300));

            Task.Run(() =>
            {
                callback(-1,100);
                tcs.SetResult(null);
                callback(-2,100);


            });
            Console.WriteLine("waiting");
            Thread.Sleep(5000);
            Console.WriteLine("done");
        }

        test(new TaskCompletionSource<object>( TaskCreationOptions.RunContinuationsAsynchronously));
        test(new TaskCompletionSource<object>());
    }

И вот (аннотированные) результаты:

    starting: RunContinuationsAsynchronously
    waiting
    -1 [11, Back, Pool] - before sleep 100
    -1 [11, Back, Pool] - after sleep 100

    -2 [11, Back, Pool] - before sleep 100

    1 [12, Back, Pool] - before sleep 1000 --> continuations are correctly executed on different threads
    2 [15, Back, Pool] - before sleep 300
    3 [13, Back, Pool] - before sleep 300

    -2 [11, Back, Pool] - after sleep 100  --> continuations correctly do not block the calling task/thread

    3 [13, Back, Pool] - after sleep 300
    2 [15, Back, Pool] - after sleep 300
    1 [12, Back, Pool] - after sleep 1000

    done

    starting: None

    -1 [13, Back, Pool] - before sleep 100
    waiting
    -1 [13, Back, Pool] - after sleep 100

    -2 [13, Back, Pool] - before sleep 100

    1 [15, Back, Pool] - before sleep 1000 --> continuations are incorrectly(?!) executed on different threads
    2 [14, Back, Pool] - before sleep 300
    3 [16, Back, Pool] - before sleep 300

    -2 [13, Back, Pool] - after sleep 100

    2 [14, Back, Pool] - after sleep 300 --> continuations incorrectly(?!) do not block the calling task/thread
    3 [16, Back, Pool] - after sleep 300
    1 [15, Back, Pool] - after sleep 1000
    done

Итак, по-видимому, мое второе предположение (без указания флага) было неверным: продолжения не выполняются синхронно - по крайней мере, не так, как я понимаю термин; они выполняются в отдельных потоках, поэтому они не блокируют вызывающий поток или друг друга.

Почему?

...