Async / Await by example - PullRequest
       30

Async / Await by example

1 голос
/ 12 апреля 2019

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

Поэтому я создал небольшие программы, чтобы увидеть, как происходит волшебство, и я получилнемного запутался:

public class Program
{
    public static async Task Main(string[] args)
    {
        var task = ToastAsync();
        Console.WriteLine($"[{Thread.CurrentThread.ManagedThreadId}] Cleaning the kitchen...");
        await task;
        Console.WriteLine($"[{Thread.CurrentThread.ManagedThreadId}] Take the toast");
    }

    public async static Task ToastAsync()
    {
        Console.WriteLine($"[{Thread.CurrentThread.ManagedThreadId}] Putting the toast");
        Console.WriteLine($"[{Thread.CurrentThread.ManagedThreadId}] Setting a timer");
        await Task.Delay(2000);
        Console.WriteLine($"[{Thread.CurrentThread.ManagedThreadId}] Toast is ready");
    }
}

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

[1] Putting the toast
[1] Setting a timer
[1] Cleaning the kitchen...
[4] Toast is ready
[4] Take the toast

Приведенный выше результат не имеет большого смысла для меня.Что на самом деле происходит?Кажется, что часть функции выполняется в одном потоке, а затем, когда она достигает точки await, она обрабатывает выполнение другому потоку ...?Я даже не знал, что это возможно. D:

Более того, я немного изменил приведенный выше пример.В основной функции вместо await task; я использовал task.Wait().И затем результаты изменились:

[1] Putting the toast
[1] Setting a timer
[1] Cleaning the kitchen...
[4] Toast is ready
[1] Take the toast

Теперь это больше похоже на пример.Это похоже на то, как таймер на тосте работал как другая «плита».Но почему он отличается от использования await?И есть ли способ получить асинхронную задачу полностью в одном потоке?Я имею в виду, что Toast is ready на thread 1 также?

ThanksAsync!

Ответы [ 2 ]

5 голосов
/ 12 апреля 2019

На что следует обратить внимание:

  1. Когда вы звоните ToastAsync, он начинает Задание Горячий (даже если вы еще не звонили await). Примечание: запуск задачи не означает запуск потока ... Что, в свою очередь, объясняет, почему «Чистка кухни». стоит за "Положить тост")

  2. Метод async будет работать до тех пор, пока не будет достигнуто первое ключевое слово await, и вернет управление вызывающей стороне.

  3. Поскольку в консольном приложении нет SyncronizationContext. Компилятор не видит необходимости создавать Continuation в вызывающем thread , что, в свою очередь, объясняет, почему "Take the toast" находится в том же потоке, что и "Toast is ready"

Примечание : Если вы чистите кухню после беспорядка, вам не нужно ее чистить заранее

Из комментариев

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

Шаблон Asnyc и Await не относится к многопоточности как таковой, он о масштабируемости и рабочих нагрузках, связанных с вводом-выводом, и / или UI отзывчивость (в UI рамки)

Взгляните на некоторые из блогов Стивена Клири на эту тему

Async and Await - Стивен Клири

1 голос
/ 12 апреля 2019

Если вы запустите тот же код из события формы Windows, вы получите ожидаемые результаты:

[1] Putting the toast
[1] Setting a timer
[1] Cleaning the kitchen...
[1] Toast is ready
[1] Take the toast

Это потому, что await по умолчанию восстанавливает контекст после ожидания, но это требует затрат, потому что это дополнительная вещь. Если вам не нужно восстановление контекста, вы можете настроить ожидание следующим образом:

await Task.Delay(2000).ConfigureAwait(false);

... и вы увидите тот же вывод, что и консольное приложение.

Имейте в виду, что ожидание - это не одновременное выполнение действий, а поддержание отзывчивости пользовательского интерфейса. Вы хотите получать новые заказы на тосты, пока готовятся тосты из предыдущих заказов.

...