如何创建可取消的任务循环?

Rog*_*son 4 c# task-parallel-library

是否可以使用System.Threading.Task.Task创建可以取消的任务循环?

流程应以Task.Delay(x ms)开始,然后继续使用用户定义的任务,然后是另一个Task.Delay(y ms),并从用户定义的任务开始重复.

var result = Task.Delay(initialDelay)
              .ContinueWith(t => dostuff..)
              .ContinueWith what goes here?
Run Code Online (Sandbox Code Playgroud)

甚至可以使用任务吗?

我可以启动一个计时器并完成它,但如果我需要取消,使用任务似乎是正确的方法,不是吗?

Ser*_*rvy 9

await 让这非常简单:

public async Task TimedLoop(Action action, 
    CancellationToken token, TimeSpan delay)
{
    while (true)
    {
        token.ThrowIfCancellationRequested();
        action();
        await Task.Delay(delay, token);
    }
}
Run Code Online (Sandbox Code Playgroud)

没有async(但仍然只是使用TPL)它有点麻烦.我通常通过将自身附加到类型变量的延续来解决这个问题Task.这样可以正常工作,但可能需要一秒钟才能绕过它.没有await它可能更容易使用一个Timer代替.

public Task TimedLoop(Action action,
    CancellationToken token, TimeSpan delay)
{
    //You can omit these two lines if you want the method to be void.
    var tcs = new TaskCompletionSource<bool>();
    token.Register(() => tcs.SetCanceled());

    Task previous = Task.FromResult(true);
    Action<Task> continuation = null;
    continuation = t =>
    {
        previous = previous.ContinueWith(t2 => action(), token)
            .ContinueWith(t2 => Task.Delay(delay, token), token)
            .Unwrap()
            .ContinueWith(t2 => previous.ContinueWith(continuation, token));
    };
    previous.ContinueWith(continuation, token);
    return tcs.Task;
}
Run Code Online (Sandbox Code Playgroud)