Используют ли новые ключевые слова C# 5.0 "async" и "await" несколько ядер?


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

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

4 57

4 ответа:

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

это попадает через цель функции, но это дает слишком много "кредита" для функции async/await.

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

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

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

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

вопрос, который вы не задавали, но, вероятно, должны были:

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

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

у Эрика Липперта есть отличный ответ; я просто хотел описать async параллелизм немного дальше.

просто "серийный" подход, где вы 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 для поддержки простого параллелизма. Однако TPL все еще существует, если вам нужно что-то более продвинутое (истинная параллельная обработка с привязкой к процессору лучше подходит для TPL). TPL хорошо играет с async/await.

я покрываю основные async параллелизм в моем на async блоге, а также" контекст", на который ссылался Эрик.

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

объект инкапсулирует асинхронное действие, которое может выполняться или не выполняться в другом потоке. Статья Эрика Липперта асинхронность в C# 5.0 Часть четвертая: это не магия рассматривается пример асинхронного программирования, который включает только один поток.

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