У меня есть два асинхронных метода: Тест1 и Тест2.
В Тест1 я хочу вызвать Тест2 "в новом потоке".
Другими словами, я хочу, чтобы отдельный «поток» выполнял Тест2, а Тест1 выполнял вызов Тест2 и не ждал его завершения.
private async Task Test2()
{
// some time-consuming work to do...
}
public async Task Test1()
{
// How to call Test2 and immediately move on to the next line and let a separate "thread" to
// execute Test2?
}
Test2 никогда не заканчивается. Я не хочу, чтобы новый System.Threading.Thread запускал Test2, потому что явный поток не может использовать преимущества асинхронности. Я хочу, чтобы асинхронный механизм обрабатывал Test2. Как это сделать?
Как использование другого потока не дает преимуществ от асинхронности? Как это согласуется с вашим запросом на выполнение отдельного потока (что и делает Task.Run
)? И что вы имеете в виду, что хотите, чтобы асинхронный механизм справился с этим?
@CharlesMager Я полагаю, что метод Test2
имеет некоторую асинхронную логику и использует в нем ожидания. Возможно, некоторые Task.Delay
для рекуррентной логики и т. д. В этом случае новый поток будет запускать только начальную логику до первого ожидания, и все продолжения в любом случае будут запланированы для ThreadPool.
Предположим, что Test2
имеет некоторую логику, интенсивно использующую процессор, и некоторые асинхронные вызовы:
private async Task Test2()
{
for (var i = 1; i < 1_000_000; i++)
{
}
await Task.Delay(TimeSpan.FromMinutes(1));
for (var i = 1; i < 1_000_000; i++)
{
}
}
Если Test2
вызывается без await
, то текущий поток выполнит логику перед первым await
в методе Test2
перед возвратом в Test1
. Это означает, что выполнение вернется к Test1
только после завершения первого цикла for
:
public async Task Test1()
{
var _ = Test2();
}
Если вам требуется, чтобы Test1
продолжил выполнение сразу после вызова Test2
, то его необходимо запланировать на другой поток из ThreadPool
, что можно сделать с помощью Task.Run
, например:
public async Task Test1()
{
var _ = Task.Run(() => Test2());
}
В этом случае у вас нет контроля, когда Test2
фактически выполняется ThreadPool
(может случиться так, что Test1
завершается даже до того, как Test2
запущен), и задача, возвращаемая Task.Run
, завершится только тогда, когда Task2
завершается или выдает ошибку. Таким образом, вы можете await
использовать задачу позже в своем коде или просто игнорировать ее, если ваша логика не заботится о результате.
И если вы не собираетесь ждать задачи от метода Test2
, стоит отлавливать и обрабатывать/записывать возможные ошибки в нем напрямую, иначе он будет молча терпеть неудачу, что может затруднить исследование проблем.
Я получил ваш комментарий и согласен, мне нравится объяснение в вашем ответе.
Task.Run(() => Test2())
будет работатьTest2
в потоке пула потоков. Однако я не уверен, что это хорошая идея просто игнорироватьTask
, возвращаемый этим. Я подозреваю, что в какой-то момент вы захотитеawait
узнать, когда он будет завершен/обработать любые исключения.