C # Async - Как это работает?
-
27-09-2019 - |
Вопрос
Microsoft объявил Visual Studio Async CTP сегодня (28 октября 2010 г.), который вводит async
а также await
Ключевые слова в C # / VB для исполнения асинхронного метода.
Сначала я подумал, что компилятор переводит ключевые слова в создание нити, но в соответствии с белая бумага И Андерс Хейлсберг PDC презентация (в 31:00) асинхронная операция происходит полностью на главной ните.
Как я могу выполнить операцию, выполненную параллельно в том же ниве? Как это технически возможно и к какой функции фактически переведена в IL?
Решение
Это работает аналогично yield return
Ключевое слово в C # 2.0.
Асинхронный метод на самом деле не является обычным последовательным методом. Он скомпилирован в состояние состояния (объект) с некоторым состоянием (локальные переменные превращаются в поля объекта). Каждый блок кода между двумя использованием await
это один «шаг» государственной машины.
Это означает, что когда начнет метод, он просто запускает первый шаг, а затем возвращается состояние машины и расписание некоторые работы, которые необходимо выполнить - когда работа выполнена, она будет запускать следующий шаг состояния. Например, этот код:
async Task Demo() {
var v1 = foo();
var v2 = await bar();
more(v1, v2);
}
Будет переведен на что-то вроде:
class _Demo {
int _v1, _v2;
int _state = 0;
Task<int> _await1;
public void Step() {
switch(this._state) {
case 0:
this._v1 = foo();
this._await1 = bar();
// When the async operation completes, it will call this method
this._state = 1;
op.SetContinuation(Step);
case 1:
this._v2 = this._await1.Result; // Get the result of the operation
more(this._v1, this._v2);
}
}
Важная часть заключается в том, что она просто использует SetContinuation
Метод Укажите, что когда операция завершается, она должна позвонить Step
метод снова (и метод знает, что он должен запускать второй бит исходного кода, используя _state
поле). Вы можете легко представить, что SetContinuation
было бы что-то вроде btn.Click += Step
, что будет работать полностью на одном потоке.
Модель асинхронного программирования в C # очень близко к F # асинхронным рабочим процессам (на самом деле, по сути то же самое, кроме некоторых технических деталей), а также написание реактивных однопоточных приложений GUI, используя async
Это довольно интересная область - по крайней мере, я так думаю - посмотреть, например, эта статья (Может быть, я должен написать версию C # сейчас :-)).
Перевод похож на итераторы (и yield return
) И на самом деле, можно было использовать итераторы для реализации асинхронного программирования в C # ранее. я написал статья о том Данное назад - и я думаю, что это все равно может дать вам некоторое понимание того, как работает перевод.
Другие советы
Как я могу выполнить операцию, выполненную параллельно в том же ниве?
Вы не можете. Асинхронность не "параллелизм" или "параллелизм". Отказ Асинхронность может быть реализована с параллелизмом, или это не может быть. Это может быть реализовано путем разрушения работы в небольшие куски, помещая каждый кусок работы на очередь, а затем выполняя каждую кусок работы всякий раз, когда нить не делает ничего другого.
У меня есть целый ряд статей в моем блоге о том, как все это работает; Один, непосредственный герман к этому вопросу, вероятно, будет идти в четверг на следующей неделе. Смотреть
http://blogs.msdn.com/b/ericlippert/archive/tags/async/
для деталей.
Как я понимаю, что async
а также await
Ключевые слова делают в том, что каждый раз async
Метод использует await
Ключевое слово, компилятор превратит оставшуюся часть метода в продолжение, которое запланировано, когда операция ASYNC завершена. Это позволяет async
Методы, чтобы вернуться к абонеру немедленно и возобновить работу при выполнении асинхронизации.
Согласно доступным документам, к нему много деталей, но если я не ошибаюсь, это суть его.
Когда я вижу, что целью асинковых методов - не запускать много кода параллельно, но чтобы порешить асинхронные методы в ряд небольших кусков, которые можно назвать по мере необходимости. Ключевым моментом является то, что компилятор будет обрабатывать всю сложную проводку обратных вызовов, используя задачи / продолжения. Это не только уменьшает сложность, но позволяет писать Async, чтобы быть написанным более или менее, как традиционный синхронный код.