Я действительно хочу пойти по маршруту Task.Run
Почему?
, но если он заканчивается использованием потоков без видимой причины, тоЭто не разрешено.
Документация гласит:
Поставляет в очередь заданную работу для выполнения в ThreadPool
Это не обязательно означает новую тему для каждого звонка Task.Run
. Возможно, но не обязательно. Все, что вы можете гарантировать, это то, что он будет работать в потоке, который не является текущим.
Вы не можете контролировать, сколько потоков создано для выполнения всей этой работы. Но рекомендация не использовать Task.Run
для операций ввода-вывода является обоснованной. Это ненужные накладные расходы без выгоды. Это будет менее эффективным.
Любое из ваших других решений будет работать нормально. Ваше последнее решение может закончиться быстрее, так как вы начинаете звонки на B()
раньше (вы ждете, пока завершится первый A()
, прежде чем начинать звонить B()
, вместо того, чтобы ждать их завершения).
Обновление на основе ответа Теодора: Мы оба правы :) Важно знать, что весь код в асинхронном методе до первого ждут (и код после, если толькоВы указываете иначе) будет работать в том же контексте, с которого он был запущен. В настольном приложении это поток пользовательского интерфейса. ожидание является асинхронным. Таким образом, поток пользовательского интерфейса освобождается во время ожидания . Но если в этом методе есть какая-то нагрузка на процессор, он заблокирует поток пользовательского интерфейса.
Поэтому Теодор говорит, что вы можете использовать Task.Run
, чтобы как можно скорее вывести его из потока пользовательского интерфейса и гарантировать, что он никогда не будетзаблокировать поток пользовательского интерфейса. Хотя это правда, вы не можете слепо использовать этот совет везде. Во-первых, вам может потребоваться сделать что-то в пользовательском интерфейсе после операции ввода-вывода, и что должно быть выполнено в потоке пользовательского интерфейса. Если вы запустили его с Task.Run
, вы должны обязательно выполнить маршалл обратно в поток пользовательского интерфейса для этой работы.
Но если вызываемый вами асинхронный метод имеет достаточную работу с привязкой к процессору, он зависаетпользовательский интерфейс, то это не строго операция ввода-вывода, а рекомендация «Использовать Task.Run
для работы с процессором и async
/ await
для ввода-вывода» по-прежнему подходит.
ВсеЯ могу сказать это: Попробуйте . Если вы обнаружите, что все, что вы делаете, замораживает пользовательский интерфейс, используйте Task.Run
. Если вы обнаружите, что это не так, то Task.Run
- это ненужные накладные расходы (не так много, заметьте, но все равно не нужно, но становится хуже, если вы делаете это в цикле, как вы).
И все это действительно относится к настольным приложениям. Если вы находитесь в ASP.NET, Task.Run
ничего не сделает для вас, если вы не попытаетесь сделать что-то параллельно. В ASP.NET нет «потока пользовательского интерфейса», поэтому не имеет значения, над каким потоком вы работаете. Вам просто нужно убедиться, что вы не блокируете поток во время ожидания (поскольку в ASP.NET имеется ограниченное количество потоков).