Возможно ли, чтобы "Returned from Foo" печатал до "In Foo"?
В той программе, в которой вы ее написали, нет, это невозможно.
Если у вас другая программа, которая запускает рабочий поток, у вас возникают все обычные проблемы упорядочения побочных эффектов между потоками.В «async / await» нет ничего особенного, что устраняет эти проблемы.
Является ли создание Задачи точкой переключения контекста или только тогда, когда она начинает ожидать или выполняет другие асинхронные действия?
Давайте уточним, что мы подразумеваем под «точкой переключения контекста».
Метод в C # может выполнять одно из четырех действий:
- Запустить навсегда
- Вернуть нормально
- Бросить
- Приостановить - это, как я думаю, вы подразумеваете под "переключением контекста".
Методотмеченные async
могут приостановить, но они приостанавливаются только тогда, когда они await
ожидают незавершенного.Ожидание завершенного ожидаемого не приостанавливается, но может выдать.
Задачи, возвращаемые с помощью async
методов: hot .Таким образом, асинхронный рабочий процесс начинается и выполняется до тех пор, пока не вернется, не сгенерирует или не приостановит работу.Можно создать «холодную» задачу с помощью конструктора Task
, и это не начнется, пока вы не вызовете Start
для нее.Обычно вы бы этого не делали, если бы не писали свой собственный планировщик задач.
Обратите внимание, что это отличается от блоков итераторов .Распространенная ошибка:
IEnumerable<int> GetMeSomeInts(int x)
{
if (x < 0)
throw new SomeException();
for (int i = 0; i < x; i += i)
yield return i;
}
Если вы скажете
var nums = GetMeSomeInts(-1); // 1
foreach(int num in nums) // 2
...
, то бросок не происходит в строке 1, это происходит в строке 2!Блоки итераторов не запускаются до первых yield
при их вызове.Они немедленно приостанавливаются и не выполняются, пока не будут повторены в foreach
.Будьте осторожны, особенно если вы работаете с асинхронными и итераторными сопрограммами в одной и той же программе.