Оригинальный ответ:
Ваш вопрос, насколько я понимаю, заключается в том, "что, если вместо реализации" ожидания "специально для асинхронности на основе задач, скорее, была реализована более общая операция потока управления вызовом с текущим продолжением?"
Ну, во-первых, давайте подумаем о том, что делает "ожидание". «await» принимает выражение типа Task<T>
, получает ожидающего и вызывает ожидающего с текущим продолжением:
await FooAsync()
становится эффективно
var task = FooAsync();
var awaiter = task.GetAwaiter();
awaiter.BeginAwait(somehow get the current continuation);
Теперь предположим, что у нас есть оператор callcc
, который принимает в качестве аргумента метод и вызывает метод с текущим продолжением. Это будет выглядеть так:
var task = FooAsync();
var awaiter = task.GetAwaiter();
callcc awaiter.BeginAwait;
Другими словами:
await FooAsync()
не более чем
callcc FooAsync().GetAwaiter().BeginAwait;
Это отвечает на ваш вопрос?
Обновление № 1:
Как указывает комментатор, ответ ниже предполагает шаблон генерации кода из версии «Предварительный просмотр технологии» функции async / await. Мы на самом деле генерируем немного другой код в бета-версии функции, хотя логически это то же самое. Нынешний кодоген выглядит примерно так:
var task = FooAsync();
var awaiter = task.GetAwaiter();
if (!awaiter.IsCompleted)
{
awaiter.OnCompleted(somehow get the current continuation);
// control now returns to the caller; when the task is complete control resumes...
}
// ... here:
result = awaiter.GetResult();
// And now the task builder for the current method is updated with the result.
Обратите внимание, что это несколько сложнее, и обрабатывает случай, когда вы «ожидаете» результат, который уже был вычислен. Нет необходимости проходить через весь ригамарол, связанный с передачей контроля вызывающей стороне и повторным поиском с того места, где вы остановились, если результат, которого вы ожидаете, фактически уже кешируется в памяти для вас прямо здесь.
Таким образом, связь между «await» и «callcc» не так проста, как это было в предварительном выпуске, но все еще ясно, что мы по сути делаем callcc для метода «OnCompleted» ожидающего. Мы просто не делаем callcc, если не обязаны.
Обновление № 2:
Как этот ответ
https://stackoverflow.com/a/9826822/88656
от Тимви указывает, что семантика вызовов / cc и await не совсем одинакова; «истинный» вызов / cc требует либо «захвата» полного продолжения метода , включая весь стек вызовов , либо, что то же самое, чтобы вся программа была переписана в стиль передачи продолжения .
Функция "ожидание" больше похожа на "совместный вызов / cc"; продолжение содержит только то, «какой текущий метод возврата задачи собирается делать дальше в точке ожидания?» Если вызывающий метода возврата задачи собирается сделать что-то интересное после завершения задачи, тогда он может бесплатно зарегистрировать его продолжение как продолжение задачи.