Подтвердить что ты не робот

Используют ли новые ключевые слова С# 5.0 "асинхронный" и "ожидающий" несколько ядер?

Два новых ключевых слова, добавленных на язык С# 5.0, async и ждут, обе из них работают рука в руке, чтобы запустить метод С# асинхронно, не блокируя вызывающий поток.

Мой вопрос: действительно ли эти методы используют преимущества нескольких ядер и работают параллельно или же метод async выполняется в том же ядре потока, что и вызывающий?

4b9b3361

Ответ 1

Два новых ключевых слова, добавленных на язык С# 5.0, являются асинхронными и ждут, оба из которых работают рука об руку, чтобы запустить метод С# асинхронно, не блокируя вызывающий поток.

Это зависит от цели этой функции, но она дает слишком много "кредитов" функции async/await.

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

Мой вопрос: действительно ли эти методы используют преимущества нескольких ядер и работают параллельно или же метод async выполняется в том же ядре потока, что и вызывающий?

Опять же, это полностью до метода, который вы вызываете. Все, что await делает, это инструктировать компилятор переписать метод в делегат, который может быть передан как продолжение асинхронной задачи. То есть, await FooAsync() означает "вызов FooAsync(), и все, что возвращается, должно быть чем-то, что представляет собой асинхронную операцию, которая только что запущена. Скажите, что когда он знает, что асинхронная операция выполнена, она должна вызвать этот делегат." Делегат обладает тем свойством, что при его вызове текущий метод, похоже, возобновляется "там, где он был выключен".

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

Вопрос, который вы не спрашивали, но, вероятно, должен иметь:

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

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

Ответ 2

Эрик Липперт имеет отличный ответ; Я просто хотел немного описать async parallelism.

Простой "последовательный" подход - это то, где вы await только одна вещь за раз:

static void Process()
{
  Thread.Sleep(100); // Do CPU work.
}

static async Task Test()
{
  await Task.Run(Process);
  await Task.Run(Process);
}

В этом примере метод Test будет помещать в очередь пул Process в пул потоков, а когда он будет завершен, он снова ставит в очередь Process в пул потоков. Метод Test завершится через ~ 200 мс. В любой момент только один поток действительно продвигает вперед.

Простым способом распараллеливания является использование Task.WhenAll:

static void Process()
{
  Thread.Sleep(100); // Do CPU work.
}

static async Task Test()
{
  // Start two background operations.
  Task task1 = Task.Run(Process);
  Task task2 = Task.Run(Process);

  // Wait for them both to complete.
  await Task.WhenAll(task1, task2);
}

В этом примере метод Test помещает Process в пул потоков дважды, а затем ждет их завершения. Метод Test завершится через ~ 100 мс.

Task.WhenAllTask.WhenAny) были введены с async/await для поддержки простого parallelism. Тем не менее, TPL по-прежнему существует, если вам нужно что-то более продвинутое (истинная параллельная обработка, связанная с процессором, лучше подходит для TPL). TPL хорошо работает с async/await.

Я расскажу о базовом async parallelism в в async сообщении блога, а также о "контексте", о котором говорил Эрик.

Ответ 3

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

Объект инкапсулирует асинхронное действие, которое может или не может выполняться в другом потоке. Eric Lippert article Асинхронность в С# 5.0 часть четвертая: она не магия рассматривает пример асинхронного программирования, который включает только один поток.

Ответ 4

Так как async и await основаны на TPL, они должны работать очень точно. По умолчанию вы должны обращаться с ними так, как если бы они выполнялись в отдельном потоке.