【问题标题】:Is there a way to use Task<T> as a waithandle for a future value T?有没有办法使用 Task<T> 作为未来值 T 的等待句柄?
【发布时间】:2011-05-27 21:43:59
【问题描述】:

我想使用一个方法中的任务返回来在以后可用时返回一个值,以便调用者可以使用等待阻塞或附加一个延续,甚至等待它。我能想到的最好的是:

 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 是我正在寻找的东西,我只是让自己的生活变得艰难吗?

【问题讨论】:

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


    【解决方案1】:

    嗯,我想我应该在发帖之前多挖一点。 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);
    

    【讨论】:

    • 我也使用 TaskCompletionSource 为我解决这个问题 - 对我来说,这是一个更优雅的等待句柄,因为它更能表达你的原始操作。表达取消或例外对于级联消费者非常有用。 :)
    【解决方案2】:

    通过调用 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
    }
    

    【讨论】:

      【解决方案3】:

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

      【讨论】:

      • 我要解决的问题是我没有 ComputeRealValueAndReturn,但是其他线程正在生成独立于请求需要该值的任务的人。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-22
      • 1970-01-01
      • 1970-01-01
      • 2018-10-13
      • 1970-01-01
      相关资源
      最近更新 更多