如果我的TaskCompletionSource公开的任务可能永远不会被调用,那么除非和直到有人在等待任务,我如何才能对结果进行计算?
例如,我希望阻止其他异步执行线程,直到使用以下函数ManualResetEvent发出信号为止。我在TaskCompleationSource的回调中完成了ThreadPool.RegisterWaitForSingleObject,这是在发出WaitHandle信号时发生的。但是,如果没有人在等待任务,那么我就不想使用RegisterWaitForSingleObject (如果在发出WaitHandle信号之后等待任务,我也不想使用WaitHandle)。
我如何更改WaitOneAsync,使计算结果的工作只有在某人等待TaskCompleationSource.Task之后才会发生?
我相信答案可能在于一个自定义的TaskAwaiter,如Scott在这里描述的 to determine if the task has been awaited,但我无法从他的例子中得到我的解决方案。:(
public static async Task<T> WaitOneAsync<T>(this WaitHandle waitHandle, Func<T> result) {
var tcs = new TaskCompletionSource<T>();
RegisteredWaitHandle rwh = null;
rwh = ThreadPool.RegisterWaitForSingleObject(
waitObject: waitHandle,
callBack: (s, t) => {
rwh.Unregister(null);
tcs.TrySetResult(result());
},
state: null,
millisecondsTimeOutInterval: -1,
executeOnlyOnce: true
);
return await tcs.Task;
}发布于 2016-10-29 19:44:10
正如usr所说,在Task被await编辑的情况下,不可能做一些事情。但如果你不介意使用一个定制的,那么你可以。
一个简单的方法是使用 from Stephen Cleary's AsyncEx
private static Task<T> WaitOneAsyncImpl<T>(WaitHandle waitHandle, Func<T> result)
{
if (waitHandle.WaitOne(0))
return Task.FromResult(result());
var tcs = new TaskCompletionSource<T>();
RegisteredWaitHandle rwh = null;
rwh = ThreadPool.RegisterWaitForSingleObject(
waitObject: waitHandle,
callBack: (s, t) =>
{
rwh.Unregister(null);
tcs.TrySetResult(result());
},
state: null,
millisecondsTimeOutInterval: -1,
executeOnlyOnce: true
);
return tcs.Task;
}
public static AsyncLazy<T> WaitOneAsync<T>(this WaitHandle waitHandle, Func<T> result)
=> new AsyncLazy<T>(() => WaitOneAsyncImpl(waitHandle, result));发布于 2016-10-29 18:18:42
这不可能完全像您描述的需求那样。当某人添加一个延续或等待一个任务时,TPL不提供事件或回调。
因此,您需要构造API,以便实际只生成所需的任务。那这个呢?
public static Func<Task<T>> CreateWaitOneAsyncFactory<T>(this WaitHandle waitHandle, Func<T> result) {
return () => WaitOneAsync(waitHandle, result);
}这将返回一个任务工厂而不是一个任务。这是欺骗,但唯一可能的解决办法是这种欺骗。
您也可以返回自定义。但这根本不涉及任务,而且它忽略了任务的可组合特性。服务生大多是C#的概念。暴露它们可能导致不干净的API。
与您的问题无关:您可以删除await tcs.Task并直接返回该任务。另外,不需要result函数。返回一个没有结果的Task。调用者可以添加一个结果,如果他们愿意的话。这使得WaitOneAsync的API更加清晰。
https://stackoverflow.com/questions/40321261
复制相似问题