С#, как запустить новый «поток» в асинхронном методе?

У меня есть два асинхронных метода: Тест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?
}
Task.Run(() => Test2()) будет работать Test2 в потоке пула потоков. Однако я не уверен, что это хорошая идея просто игнорировать Task, возвращаемый этим. Я подозреваю, что в какой-то момент вы захотите await узнать, когда он будет завершен/обработать любые исключения.
Charles Mager 10.04.2022 13:00

Test2 никогда не заканчивается. Я не хочу, чтобы новый System.Threading.Thread запускал Test2, потому что явный поток не может использовать преимущества асинхронности. Я хочу, чтобы асинхронный механизм обрабатывал Test2. Как это сделать?

Silly Dude 10.04.2022 13:07

Как использование другого потока не дает преимуществ от асинхронности? Как это согласуется с вашим запросом на выполнение отдельного потока (что и делает Task.Run)? И что вы имеете в виду, что хотите, чтобы асинхронный механизм справился с этим?

Charles Mager 10.04.2022 13:21

@CharlesMager Я полагаю, что метод Test2 имеет некоторую асинхронную логику и использует в нем ожидания. Возможно, некоторые Task.Delay для рекуррентной логики и т. д. В этом случае новый поток будет запускать только начальную логику до первого ожидания, и все продолжения в любом случае будут запланированы для ThreadPool.

Andrii Litvinov 10.04.2022 13:25
Получение данных из формы с помощью JavaScript - краткое руководство
Получение данных из формы с помощью JavaScript - краткое руководство
Получить данные из формы с помощью JS очень просто: вы запрашиваете элемент формы, передаете его конструктору new FormData() и, наконец, получаете...
Пользовательские правила валидации в Laravel
Пользовательские правила валидации в Laravel
Если вы хотите создать свое собственное правило валидации, Laravel предоставляет возможность сделать это. Создайте правило с помощью следующей...
3 метода стилизации элементов HTML
3 метода стилизации элементов HTML
Когда дело доходит до применения какого-либо стиля к нашему HTML, существует три подхода: встроенный, внутренний и внешний. Предпочтительным обычно...
Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно...
Flatpickr: простой модуль календаря для вашего приложения на React
Flatpickr: простой модуль календаря для вашего приложения на React
Если вы ищете пакет для быстрой интеграции календаря с выбором даты в ваше приложения, то библиотека Flatpickr отлично справится с этой задачей....
2
4
43
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Предположим, что 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, стоит отлавливать и обрабатывать/записывать возможные ошибки в нем напрямую, иначе он будет молча терпеть неудачу, что может затруднить исследование проблем.

Я получил ваш комментарий и согласен, мне нравится объяснение в вашем ответе.

Maytham 10.04.2022 13:38

Другие вопросы по теме