Почему этот асинхронный асинхронный / многопоточный? - PullRequest
0 голосов
/ 18 февраля 2019

Я следую за статьей, показывающей, что асинхронные задачи не являются потоками.https://blogs.msdn.microsoft.com/benwilli/2015/09/10/tasks-are-still-not-threads-and-async-is-not-parallel/

В своем примере они создают асинхронный вызов, показывая это, создав 3 задачи, каждая из которых выполняет цикл, который приостанавливается на несколько секунд.Я воссоздал его в консольном (помеченном как STAThread) приложении.

Однако в моем коде ниже я ожидал, что в обоих примерах это займет те же 15 секунд (5 секунд для каждой задачи), как указано встатья.Тем не менее, это занимает всего 5 секунд за секунду и поэтому запускает все 3 одновременно, в результате чего для моего второго примера требуется 5 секунд.Первоначальная статья заняла 5 секунд, но я изменил ее на задержку в 1 секунду, чтобы сделать ее более очевидной.

Может кто-нибудь объяснить, что происходит и почему он работает с нарезкой?

    class AsyncTest
    {
        Stopwatch sw = new Stopwatch();
        internal void Tests()
        {
            DoASynchronous1();
            //update below to be DoAsync2 and repeat
        }

        private void DoASynchronous1()
        {
            sw.Restart();
            var start = sw.ElapsedMilliseconds;
            Console.WriteLine($"\nStarting ASync Test, interval 1000ms");
            Task a=DoASync1("A",1000);     //change these to 2           
            Task b=DoASync1("B",1000);                
            Task c=DoASync1("C",1000);                
            Task.WaitAll(a, b, c);
            sw.Stop();
            Console.WriteLine($"Ended Sync Test. Took {(sw.ElapsedMilliseconds - start)} mseconds");
            Console.ReadKey();
        }

        //this runs synchronously showing async is not threaded
        //this takes 15 seconds
        private async Task DoASync1(string v, int delay)
        {
            //loop for 5 seconds
            for (int i = 1; i <= 5; i++)
            {
                await Task.Delay(0); //or simply omit
                var startTime = sw.ElapsedMilliseconds;
                while (sw.ElapsedMilliseconds < startTime+(delay)) { }
                Console.WriteLine($"{v}:{i}");
            }
        }

        //this is taking 5 seconds
        private async Task DoASync2(string v, int delay)
        {
            //loop for 5 seconds
            for (int i = 1; i <= 5; i++)
            {
                await Task.Delay(100);
                var startTime = sw.ElapsedMilliseconds;
                while (sw.ElapsedMilliseconds < startTime + delay) { }
                var endtime = sw.ElapsedMilliseconds;
                Console.WriteLine($"{v}:{endtime}");
            }
        }

    }
}

1 Ответ

0 голосов
/ 18 февраля 2019

Ключевым моментом здесь является отсутствие контекста синхронизации.Связанная статья представляет собой приложение WPF, которое имеет контекст синхронизации в своем потоке Main / UI.Созданное вами консольное приложение не будет иметь его вообще.

Результатом этого является то, что в статье говорится, например:

Когда вы «ожидаете» асинхронную задачу,остальная часть вашего метода будет продолжать работать в том же контексте, в котором он был запущен.В WPF этот контекст является потоком пользовательского интерфейса.

Это не относится к вашему примеру.После Task.Delay ваш код возобновит работу в потоке пула потоков.Это позволяет всем трем задачам выполняться параллельно.

Это почти то же самое, что и в последующем использовании статьи ConfigureAwait(false), что предотвращает возобновление выполнения в захваченном контексте синхронизации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...