将任务转换为任务<unit>的最有效方法?

时间:2015-12-17 11:46:51

标签: c# .net parallel-processing task-parallel-library system.reactive

我有一个高吞吐量排队安排,我接受Func<Task>并希望将其投射到Func<Task<System.Reactive.Unit>>以适应下游Rx系统。

由于Unit.Default是唯一的值,感觉这应该很容易,但我希望它尽可能高效。我希望以正确的方式通过原始Task的所有例外情况。

我目前的做法是:

public Task<Unit> QueueTaskRx(Func<Task> task)
{
    Func<Task<Unit>> f = async () =>
    {
        await task();
        return Unit.Default;
    };

    return QueueTask(f);
}

但我担心async/await

的开销

也许另一种更有效的方式是:

public Task<Unit> QueueTaskRx(Func<Task> task)
{
    Func<Task<Unit>> f = () => task().ContinueWith(_ =>
    {
        // What other cases do I need to consider here??
        if (_.IsFaulted && _.Exception != null)
            throw _.Exception.InnerException;

        return Unit.Default;
    }, TaskContinuationOptions.ExecuteSynchronously);

    return QueueTask(f);
}

但这并不安全,而且更复杂,分支等

有没有人有更好的方法?

2 个答案:

答案 0 :(得分:3)

我会使用async / await,同时添加ConfigureAwait(false)

可以使用ContinueWith执行此操作,但这只会节省一些非常少的时间(例如单个按位标记检查和单个引用副本)。复杂性会花费很多:

  • ContinueWith应始终指定TaskScheduler
  • 除了例外情况,您应该处理取消,因为Task专门处理了取消。

对于其他陷阱,请参阅我的Tour of Task博客系列(遗憾的是仍然不完整),我尝试使用“旧”API枚举所有问题(例如,ContinueWith)。

答案 1 :(得分:1)

我实施了您需要的内容here。我使用另一个名为Then的任务扩展,其灵感来自Stephen Toub's blog post