有没有一种方法可以使用Task<;T>;作为未来值T的等待句柄
本文关键字:gt 未来 句柄 等待 方法 一种 可以使 lt 有没有 Task | 更新日期: 2023-09-27 17:57:47
我想使用一个方法的Task return来返回一个值,当它在以后可用时,这样调用者就可以使用Wait来阻止或附加一个continuation,甚至等待它。我能想到的最好的方法是:
public class Future<T> {
private ManualResetEvent mre = new ManualResetEvent();
private T value;
public async Task<T> GetTask() {
mre.WaitOne();
return value;
}
public void Return(T value) {
this.value = value;
mre.Set();
}
}
主要问题是mre。WaitOne()正在阻塞,所以我假设每次调用GetTask()都会调度一个新线程来阻塞。有没有一种方法可以以异步方式等待WaitHandle,或者已经有一个助手来构建等效的功能?
编辑:好吧,TaskCompletionSource是我想要的吗?我只是在让自己的生活变得艰难?
好吧,我想我应该在发布之前多了解一下。TaskCompletionSource
正是我想要的
var tcs = new TaskCompletionSource<int>();
bool completed = false;
var tc = tcs.Task.ContinueWith(t => completed = t.IsCompleted);
tcs.SetResult(1);
tc.Wait();
Assert.IsTrue(completed);
通过调用WaitHandle.WaitOne()阻塞线程是不好的,但这就是事件的工作方式,所选的答案没有多大意义,因为它不会异步执行任何操作。
然而,.NET框架可以利用线程池中的工作线程同时等待多个事件(请参阅ThreadPool.RegisterWaitForSingleObject)-如果您需要同时等待多个子WaitHandles,这将提高应用程序中的总体资源利用率。
因此,您可以注册等待工作线程的WaitHandle,并使用所需的continuation设置回调。使用AsyncWaitHandle扩展库(NuGet),这可以在一行中完成:
var mre = new ManualResetEvent();
T myValue = ...;
Task<T> futureValueTask = mre.WaitOneAsync().ContinueWith(() => myValue);
总的来说,我谦虚的建议是审查代码并这样做:
async Task MyCode()
{
var mre = new ManualResetEvent();
StartDoingSmthAsynchronouslyThatPulsesTheEvent(mre);
await mre;
// finish routine here when the event fires
}
难道不能利用TaskEx.WhenAll(t1, t2, t3...)
来完成等待吗。你需要一个真正的任务来代表工作的完成,但如果你说了这样的话:
private Task<T> myRealWork;
private T value;
// ...
public async Task<T> GetTask()
{
value = await TaskEx.WhenAll(myRealWork);
return value;
}
尽管您可能也可以等待myRealWork任务。我看不出在您的代码中实际计算值的位置。这可能需要类似的东西:
public async Task<T> GetTask()
{
value = await TaskEx.RunEx(() => ComputeRealValueAndReturnIt());
return value;
}