Объяснение основного потока Выполнение с ключевым словом await - PullRequest
0 голосов
/ 23 июня 2019

Я прочитал дюжину статей об async / await, и все они были отлично прочитаны.Но во всех этих статьях некоторые заблуждения / вопросы не рассматривались.Я также видел на этом форуме (это потрясающее сообщение) , но у меня нет четкого объяснения, поэтому я ищу ваши глубокие знания по этому вопросу.

Пример

В приведенном ниже примере Console App, поскольку контекст синхронизации не поддерживается, возвращаются идентификаторы потоков, а именно 1 и 5.

( Аналогичный пример с графическим интерфейсом будет работать на тот же поток , где поддерживается контекст синхронизации. )

using System;
using System.Threading;
using System.Threading.Tasks;

namespace AsyncConcept
{
    class Program
    {
        static void Main(string[] args)
        {
            AsyncMethod();
            Console.WriteLine("Main Thread: " + (int)AppDomain.GetCurrentThreadId());
            Console.ReadLine();
        }

        public static async void AsyncMethod()
        {
            await Task.Delay(TimeSpan.FromSeconds(5));
            Console.WriteLine("AsyncMethod Thread: " + (int)AppDomain.GetCurrentThreadId());
            Console.ReadLine();
        }
    }
}

Вопросы

Когда мы используем ключевое слово await с, скажем, IВызов / O или вызов API, происходит ли операция ожидания только в главном потоке?

a) Если да, то почему основной поток (поток пользовательского интерфейса в случае GUI) продолжает работу с оставшейся частью метода одновременно?

b) Если нет, то это нарушает теорию асинхронного вызова без потоков и ждет.

1 Ответ

1 голос
/ 23 июня 2019

Когда мы используем ключевое слово await с, скажем, вызовом ввода-вывода или вызовом API, происходит ли операция await только в главном потоке?

await происходит в любом потоке, в котором работает этот метод. В этом случае AsyncMethod вызывается в основном потоке, а await происходит в основном потоке. Если AsyncMethod был вызван потоком пользовательского интерфейса, то await произойдет в потоке пользовательского интерфейса.

Я думаю, вы думаете, что await каким-то образом "запускает" асинхронную операцию, но это совсем не то, что происходит. Что я имею в виду под await «происходящим» , так это то, что await:

  1. Проверяет, завершено ли его ожидание (в этом случае «ожидание» - это задание, возвращаемое с Task.Delay). Если он уже завершен, он продолжает выполнять метод синхронно.
  2. Если ожидаемое не завершено, await (по умолчанию) будет захватывать текущий контекст, а затем использовать его, чтобы запланировать продолжение выполнения этого метода после завершения ожидаемого. Затем await возвращается.

Обратите внимание, что если ожидаемое не завершено, метод возвращается. В обычном случае он возвращает неполное задание, которое завершается, когда завершается метод async; в этом случае нет возвращаемого типа, поэтому вызывающий код не может легко узнать, когда завершится метод async.

a) Если да, то почему основной поток (поток пользовательского интерфейса в случае графического интерфейса) продолжает работу с оставшейся частью метода одновременно?

Поскольку ожидаемое не завершено, await возвращается из метода. Остальная часть метода будет запущена, когда ожидаемое завершится.

...