将 Task 转换为 Task<Unit> 的最有效方法?
Most efficient way to convert Task to Task<Unit>?
我有一个高吞吐量队列安排,我接受了一个 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);
}
但这并不安全,而且更复杂,分支等
有没有人有更好的方法?
我实现了你所需要的here. I used another extension for tasks called Then
which was inspired by Stephen Toub's blog post。
我会使用 async
/await
,同时添加一个 ConfigureAwait(false)
.
你 可以 使用 ContinueWith
来完成它,但这只会为你节省一些非常小的时间(比如单个按位标志检查和单个参考副本).这将花费很多复杂性:
ContinueWith
应始终指定 TaskScheduler
.
- 除了异常之外,您还应该处理取消,因为
Task
对此进行了特殊处理。
对于其他陷阱,请参阅我的 Tour of Task
博客系列(遗憾的是仍然不完整),我在其中尝试列举使用 "old" API 可能导致的所有问题(例如,ContinueWith
).
我有一个高吞吐量队列安排,我接受了一个 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);
}
但这并不安全,而且更复杂,分支等
有没有人有更好的方法?
我实现了你所需要的here. I used another extension for tasks called Then
which was inspired by Stephen Toub's blog post。
我会使用 async
/await
,同时添加一个 ConfigureAwait(false)
.
你 可以 使用 ContinueWith
来完成它,但这只会为你节省一些非常小的时间(比如单个按位标志检查和单个参考副本).这将花费很多复杂性:
ContinueWith
应始终指定TaskScheduler
.- 除了异常之外,您还应该处理取消,因为
Task
对此进行了特殊处理。
对于其他陷阱,请参阅我的 Tour of Task
博客系列(遗憾的是仍然不完整),我在其中尝试列举使用 "old" API 可能导致的所有问题(例如,ContinueWith
).