我想从方法中使用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我正在寻找什么,我只是在为自己的生活而努力?
答案 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;
}