问题描述
|
我想使用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是我正在寻找的东西吗,而我只是使自己的生活艰难?
解决方法
好吧,我想我应该在发布之前多挖一点。
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以便在辅助线程上等待,然后使用所需的连续性设置回调。
使用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
}
, 您不能只是利用5英镑来等待。您需要一个代表工作完成的真实任务,但是如果您说出类似以下内容:
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;
}