.net 继续执行任务<;T>;完成一项任务<;U>;不阻塞结果

.net 继续执行任务<;T>;完成一项任务<;U>;不阻塞结果,.net,asynchronous,.net,Asynchronous,我有两个异步方法Task DoInt()和Task DoString(int-value)。我有第三个异步方法Task DoBoth(int value),其目标是异步执行DoInt(),将其输出到DoString(int),并将结果作为DoBoth()的结果 重要的制约因素是: 我可能没有DoInt()或DoString()的源代码,所以我不能 修改它们 我不想在任何时候阻挡 一个任务的输出(结果)必须作为输入传递给下一个任务 最终输出(结果)是我想要的DoBoth()的结果 关键是我已经有了

我有两个异步方法
Task DoInt()
Task DoString(int-value)
。我有第三个异步方法
Task DoBoth(int value)
,其目标是异步执行
DoInt()
,将其输出到
DoString(int)
,并将结果作为
DoBoth()的结果

重要的制约因素是:

  • 我可能没有
    DoInt()
    DoString()
    的源代码,所以我不能 修改它们
  • 我不想在任何时候阻挡
  • 一个任务的输出(结果)必须作为输入传递给下一个任务
  • 最终输出(结果)是我想要的
    DoBoth()的结果
  • 关键是我已经有了异步的方法(即返回任务),并且我希望在任务之间传递数据,而不在过程中阻塞,在初始任务中返回最终结果。除了在以下代码中不阻塞之外,我可以执行以下所有操作:

    代码示例:

    // Two asynchronous methods from another library, i.e. can't be changed
    Task<int> DoInt(); 
    Task<string> DoString(int value);
    
    Task<string> DoBoth()
    {
        return DoInt().ContinueWith<string>(intTask => 
        {
            // Don't want to block here on DoString().Result
            return DoString(intTask.Result).Result; 
        });
    }
    
    //来自另一个库的两个异步方法,即无法更改
    任务DoInt();
    任务DoString(int值);
    任务DoBoth()
    {
    return DoInt().ContinueWith(intTask=>
    {
    //不想在DoString()上阻止此处。结果
    返回DoString(intTask.Result).Result;
    });
    }
    

    既然
    taskdostring(int)
    已经是一个异步方法,我如何干净地为它创建一个非阻塞的继续?实际上,我希望从现有任务而不是从函数创建延续。

    您可以使用as编写整个链:


    作为使用C#5和.NET 4.5(或异步目标包)的额外工具,您可以将其编写为:

    async Task<string> DoBoth(int value)
    {
        int first = await DoInt(value);
        return await DoString(first);
    }
    
    异步任务DoBoth(int值)
    {
    int first=等待完成(值);
    返回等待字符串(第一个);
    }
    
    在函数式语言中,您需要类似flatMap的方法

    DoInt
    是否将int作为参数?你在你的帖子中有两种方式…@ReedCopsey-我修复了DoInt()的签名。在示例中,它是否有参数并不重要,但我的示例中的不一致性令人困惑:)为了清晰起见,还重命名了valueTask=>intTask。
    valueTask.Result
    不会阻止,而是
    DoString(valueTask.Result)。Result
    将阻止,直到
    DoString()
    返回的任务完成。我所说的阻塞,并不是指原始调用方被阻塞;我的意思是,一个线程可能处于空闲状态,等待另一个任务完成(在本例中,该线程正在运行一个异步委托,但从系统资源的角度来看,它仍然是一个线程)。太棒了!里德,如果你能澄清的话;即使您获取了
    valueTask.Result
    ,也不会出现阻塞吗?@AndersGustafsson否-在获取结果时,您处于继续状态
    valueTask
    保证在该点完成,因此
    .Result
    变为非阻塞。(但是,如果任务被取消或失败,它仍可能引发异常,但它将永远不会阻止。)@MikeJansen使用Unwrap(),如我所示,可以避免放置第二个
    .Result
    ,这就是为什么它永远不会阻止。如图所示,代码中没有浪费资源。@MikeJansen仅供参考-我还展示了如何使用VS2012编写此代码。。。
    Task<string> DoBoth()
    {
        return DoInt().ContinueWith(t => DoString(t.Result)).Unwrap();
    }
    
    async Task<string> DoBoth(int value)
    {
        int first = await DoInt(value);
        return await DoString(first);
    }