#c# #asynchronous #async-await
Вопрос:
У меня есть код, который выглядит примерно так:
Я пытался избежать включения его в задачу.Запуск, потому что он асинхронный и должен нормально работать в основном потоке
Однако он не выполняет переключение контекста (и будет выполняться вечно), если я не вставлю задачу.Задержка в цикле
Есть ли лучший способ добиться этого (без Task.Run)?
var tasks = new List<Task>();
var cts = new CancellationTokenSource();
tasks.Add(DoSomething(cts.Token));
cts.Cancel();
Task.WaitAll(tasks.ToArray());
Console.WriteLine("Done");
async Task DoSomething(CancellationToken ct)
{
while (!ct.IsCancellationRequested)
{
await Task.CompletedTask;
await Task.Delay(1); // Without this is doesn't do context switch
}
}
Я пытаюсь отменить модульный тест, когда у меня большая рабочая нагрузка, и столкнулся с этой проблемой.
Комментарии:
1. В чем проблема с использованием
Task.Delay
?2. попробуйте Task. Выход?
3. Задача. Выход идеальный! Спасибо, я не знал об этом. Вы можете опубликовать в качестве ответа, если хотите, я приму его
4.
async..await
само по себе не заставляет код выполняться асинхронно. Это позволяет сделать это только элегантным и прозрачным способом. Таким образом, асинхронный метод всегда будет выполняться синхронно до момента, когда вы принудительно переключаете контекст (например, используяawait Task.Run(...)
await Task.Yield
или ожидая другого асинхронного метода с асинхронным кодом).5. @RedRidingHood добавил ответ
Ответ №1:
Попробуйте
async Task DoSomething(CancellationToken ct)
{
while (!ct.IsCancellationRequested)
{
//await Task.CompletedTask; //you can omit this line
await Task.Yield();
}
}
Ответ №2:
Если вы хотите имитировать отменяемую операцию, самый простой способ, вероятно, таков:
Task DoSomething(CancellationToken cancellationToken)
{
return Task.Delay(Timeout.Infinite, cancellationToken);
}
cancellationToken
Параметр имеет отменяющую семантику, что означает, что при отмене токена Task
он перейдет в Canceled
состояние. Если вы хотите, чтобы у него была семантика остановки, которая является нестандартной семантикой для a CancellationToken
, вы могли бы сделать это:
async Task DoSomething(CancellationToken stoppingToken)
{
try { await Task.Delay(Timeout.Infinite, stoppingToken); }
catch (OperationCanceledException) { }
}
Теперь, когда токен отменяется, Task
он переходит в RanToCompletion
состояние. Имейте в виду, что крайне редко можно увидеть CancellationToken
параметр с семантикой остановки в стандартных библиотеках .NET.