有没有办法使用Task <t>作为未来值T的等待句柄?</t>

时间:2011-05-27 21:44:00

标签: c# task-parallel-library async-await async-ctp

我想从方法中使用Task返回值,以便在以后可用时返回该值,以便调用者可以阻止使用Wait或附加延续甚至等待它。我能想到的最好的是:

 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我正在寻找什么,我只是在为自己的生活而努力?

3 个答案:

答案 0 :(得分:11)

嗯,我想我应该在张贴之前挖一下。 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);

答案 1 :(得分:3)

通过调用WaitHandle.WaitOne()来阻止线程是坏事,但是事件是如何工作的,并且选择的答案没有多大意义,因为它不会异步执行任何操作。

但是,.NET框架可以利用线程池中的工作线程同时等待多个事件(请参阅ThreadPool.RegisterWaitForSingleObjec t) - 如果您需要等待,这将提高应用程序的整体资源利用率同时在多个WaitHandles上。

所以你可以做的是注册WaitHandle以等待工作线程,并设置回调所需的延续。 使用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
}

答案 2 :(得分:0)

你不能只利用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;
}