.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);
}