【问题标题】:How to create a cancelled task如何创建取消的任务
【发布时间】:2014-10-20 01:41:54
【问题描述】:

我正在编写一个 Stream 类并在 ReadAsync 方法中被阻止。请看一下代码,我认为它可以更好地解释我的英语情况。

public override Task<int> ReadAsync(byte[] buffer, int offset, int count, System.Threading.CancellationToken cancellationToken)
{
    if (!cancellationToken.IsCancellationRequested)
    {
        return _connection.ReceiveAsync(new ArraySegment<byte>(buffer, offset, count));
    }
    return // <---------------    what here?
}

使用 ILSpy 我可以看到其他 Stream 类返回一个已取消的任务,如下所示:

return new Task<TResult>(true, default(TResult), TaskCreationOptions.None, cancellationToken); 

但是,Task 的构造函数是内部的,我无法调用它。

Google 根本没有帮助我。

【问题讨论】:

    标签: task-parallel-library async-await c#-5.0 cancellation-token


    【解决方案1】:

    我知道创建取消任务的最直接方法是使用TaskCompletionSource

    var tcs = new TaskCompletionSource<int>();
    tcs.TrySetCanceled();
    return tcs.Task;
    

    如果你之前没用过,TaskCompletionSource 提供了一个“promise-style”任务,基本上可以让你说,“这里,现在拿着这个Task,我会提供结果(或者随时报告错误/取消)。”当您想自己安排/协调工作时,它很有用,而不是简单地依赖TaskScheduler

    或者,如果您使用async/await 重写您的方法,您可以强制取消异常自动传播到结果Task

    public async override Task<int> ReadAsync(
        byte[] buffer,
        int offset,
        int count,
        CancellationToken cancellationToken)
    {
        cancellationToken.ThrowIfCancellationRequested();
    
        return await _connection.ReceiveAsync(
            new ArraySegment<byte>(
                buffer,
                offset,
                count));
    }
    

    【讨论】:

    • 我不喜欢调用 ThrowIfCancellationRequested 的想法,因为抛出异常和展开堆栈会产生必要的运行时开销 - 当我可以只做 if( token.IsCancelationRequested ) return Task.FromCanceled( token ) 时,我该怎么做async 方法?
    • @戴你不行;将方法标记为async Task&lt;T&gt; 后,必须返回T。我不会担心抛出异常的开销。针对常见情况进行优化。取消应该是不常见的。这是在 async 方法中传播取消的惯用方式。
    【解决方案2】:

    next version of .Net (v4.5.3) 正在添加一种利用该内部构造函数创建已取消任务的方法。有通用和非通用版本:

    var token = new CancellationToken(true);
    Task task = Task.FromCanceled(token);
    Task<int> genericTask = Task.FromCanceled<int>(token);
    

    请记住,在调用FromCanceled之前必须取消正在使用的CancellationToken

    【讨论】:

      猜你喜欢
      • 2014-03-29
      • 1970-01-01
      • 2016-12-27
      • 2013-12-31
      • 1970-01-01
      • 2018-09-05
      • 2015-05-31
      • 2017-12-09
      • 1970-01-01
      相关资源
      最近更新 更多