Task.Delay与Task.Yield融合?

Kug*_*uBu 1 c# task

我正在尝试做类似光纤的代码,我可以进入任务并摆脱它.我试过的代码:

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( );
    }
}
Run Code Online (Sandbox Code Playgroud)

它运行良好,但是当我Thread.Sleep在Task\Main上下文中调用它时会占用大量的CPU,因为它在循环中运行而在另一侧没有停止.当我尝试await Task.Delay( int.MaxValue, (_m\_t) );而不是await Task.Yield( );,它没有消耗大量的CPU,而是有时因为Task不会屈服于另一个而陷入僵局Task.

我的问题是,如何融合Task.Delay,Task.Yield所以它不消耗大量的CPU,但仍然可以让其他任务工作?

Ree*_*sey 6

您可以Register使用a CancellationToken在标记源时通知您,而不是执行while循环:

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;
}
Run Code Online (Sandbox Code Playgroud)

这避免了有效自旋等待您是通过使用whileTask.Yield和直接标志着在消除发生完成了任务.