如果我的TaskCompletionSource公开的Task可能永远不会被调用,那么除非有人等到任务等待,我如何才能将结果的计算推迟?
例如,我想阻止其他异步执行线程,直到使用以下函数WaitOneAsync发出ManualResetEvent信号为止。我在ThreadPool.RegisterWaitForSingleObject的回调中完成TaskCompleationSource,这在发出WaitHandle信号时发生。但是,如果没有人等待任务,那么我就不想注册RegisterWaitForSingleObject(如果在信号WaitHandle之后等待任务,我也不想注册RegisterWaitForSingleObject)。
如何更改WaitOneAsync,以便将结果计算到RegisterWaitForSingleObject的工作仅在有人等待TaskCompleationSource.Task之后发生?
我相信答案可能在于斯科特·张伯伦(Scott Chamberlain)此处Implement AsyncManualResetEvent using Lazy<T> to determine if the task has been awaited中描述的自定义TaskAwaiter,但我不能完全从他的示例中得到解决方案... :(
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;
}
最佳答案
正如usr所说,无法对Task
被ed编码的代码使用react。但是,如果您可以使用自定义的awaitable,则可以。
一种简单的方法是使用 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));