Я пытаюсь сделать волоконно-подобный код, который я могу получить в задаче и выйти из него. Код, который я пробовал:
class TaskActivity {
CancellationTokenSource _m=new CancellationTokenSource( int.MaxValue )
,_t=new CancellationTokenSource( int.MaxValue );
public async Task PauseTask( ) { //call and await it when I want to pause task inside itself
_m.Cancel( );
_t = new CancellationTokenSource( int.MaxValue );
while( !_t.IsCancellationRequested )
await Task.Yield( );
}
public async Task ResumeTask( ) { //call and wait for it when I want to resume a task from the main context
_t.Cancel( );
_m = new CancellationTokenSource( int.MaxValue );
while( !_m.IsCancellationRequested )
await Task.Yield( );
}
}
Он работает хорошо, но он потребляет много CPU, когда я вызываю Thread.Sleep
в контексте Task\Main, потому что он работает в цикле без остановки на другой стороне. Когда я попытался await Task.Delay( int.MaxValue, (_m\_t) );
вместо await Task.Yield( );
, он не потреблял много CPU, но вместо этого он затормозил иногда, потому что Task
не уступает другой Task
.
Мой вопрос заключается в том, как сплавить Task.Delay
и Task.Yield
чтобы он не потреблял много процессора, но все же позволял другим задачам работать?
Вместо выполнения цикла while вы можете Register
в CancellationToken
чтобы уведомить вас, когда источник помечен:
public Task PauseTask( )
{
_m.Cancel( );
_t = new CancellationTokenSource( int.MaxValue );
// Make a task yourself
var task = new TaskCompletionSource<bool>();
_t.Token.Register(() => task.TrySetResult(true)); // Mark the task done
return task.Task;
}
Это позволяет избежать эффективного спина ждать вы используете через в while
с Task.Yield
и непосредственно исполняется задача завершается, когда происходит отмена.
ResumeTask
он зашёл в тупик. Он переключился наTask
, переключился обратно в основной контекст, снова наTask
и умер. Кстати в основном контексте я использовалactivity.ResumeTask( ).Wait( );
, все нормально?await
, а не вызыватьWait
для задач ...