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

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

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

4 ответа

Решение

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

Это соответствует цели этой функции, но придает слишком большое значение функции асинхронизации / ожидания.

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

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

Опять же, это полностью зависит от метода, который вы вызываете. Все это await Он указывает компилятору переписать метод в делегат, который может быть передан как продолжение асинхронной задачи. Это 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.WhenAll (а также Task.WhenAny) были введены с async / await поддерживать простой параллелизм. Тем не менее, TPL все еще там, если вам нужно что-то более продвинутое (истинная параллельная обработка с ЦП лучше подходит для TPL). TPL хорошо играет с async / await,

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

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

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

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

Другие вопросы по тегам