有没有一种方法可以使用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是我想要的吗?我只是在让自己的生活变得艰难?

有没有一种方法可以使用Task<;T>;作为未来值T的等待句柄

好吧,我想我应该在发布之前多了解一下。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;
}