Используют ли новые ключевые слова C # 5.0 «async» и «await» несколько ядер? - PullRequest
60 голосов
/ 28 марта 2012

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

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

Ответы [ 4 ]

96 голосов
/ 28 марта 2012

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

, который получаетчерез цель функции, но она слишком много "кредитует" функцию асинхронного / ожидания.

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

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

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

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

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

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

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

67 голосов
/ 28 марта 2012

Эрик Липперт имеет отличный ответ;Я просто хотел описать 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 блоге , а также "контекст", который Эрикнамекает на.

4 голосов
/ 28 марта 2012

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

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

2 голосов
/ 28 марта 2012

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

...