Может ли контекст `Task` переключаться перед первым` await`? - PullRequest
0 голосов
/ 05 октября 2018

Является ли создание Task точкой переключения контекста или только когда она начинает await или выполняет другие асинхронные действия?

Например, если у меня есть следующие функции:

async Task Foo()
{
  Console.WriteLine("In Foo");
  await bar();
}

void CallFoo()
{
  var task = Foo();
  Console.WriteLine("Returned from Foo");
  task.Wait();
}

Возможно ли "Возвращено из Foo" печатать до "In Foo"?

Ответы [ 2 ]

0 голосов
/ 06 октября 2018

Возможно ли, чтобы "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.Будьте осторожны, особенно если вы работаете с асинхронными и итераторными сопрограммами в одной и той же программе.

0 голосов
/ 05 октября 2018

Из спецификации языка C # 5.0 :

10.15.1 Оценка асинхронной функции, возвращающей задачу

Вызоввозвращающая задачу асинхронная функция вызывает создание экземпляра возвращенного типа задачи.Это называется задача возврата асинхронной функции.Первоначально задача находится в состоянии неполное .

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

В примере, приведенном в вопросе, Foo будет немедленно оцениваться до его первого значения await до того, как управление будет возвращено вызывающему.«In Foo» всегда будет печататься до «Возвращено из Foo».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...