我正在翻译所有f#代码以使用异步。我发现它比预期的更难,我想知道是否有更好的方法或者我错过了什么。
采取以下两个功能:
let test1() =
let y =
let x =
let z = f()
5 + z
x + 6
y + 3
let test2() =
let z = f ()
let x = 5 + z
let y = x + 6
y + 3
这些函数完全等效,但我的代码恰好采用test1的风格。
似乎编写为test1的代码转换为异步代价非常昂贵。例如,假设函数f()变为异步:
let f () =
async{
return 3
}
问题是如何翻译test1和test2。事实证明test2很容易修复:
let test2Async() =
async{
let! z = f ()
let x = 5 + z
let y = x + 6
return y + 3
}
你只需输入一个“async {}”,一个“!”和一个“回归”。
但是如果你对test1做同样的事情,它就不会编译:
let test1AsyncWrong() =
async{
let y =
let x =
let! z = f() // ERROR HERE: we are not in a computation expression, so I can't use !
5 + z
x + 6
return y + 3
}
据我所知,您需要做的是正确翻译test1:
let test1AsyncRight() =
async{
let! y =
async{
let! x =
async{
let! z = f()
return 5 + z
}
return x + 6
}
return y + 3
}
请注意,我需要输入async {} 三次,再加上“!”三次并“返回”三次。
这似乎是一种不必要且违反直觉的并发症。感觉有什么不对劲。如果必须这样做,翻译这样的代码需要几天时间。
我错过了什么吗?这是怎么回事?谢谢你的帮助。
答案 0 :(得分:3)
我不认为将async
嵌套在另一个async
中的方法更好。但它可能更糟糕,想象一下如果没有计算工作流程就可以。
我重构" asyncified"代码摆脱嵌套。所以对于你的例子,我有类似的东西 - 一个对async
一无所知的常规函数,以及只关心将各个部分组合在一起的let test1 z =
let y =
let x =
5 + z
x + 6
y + 3
let test1Async() =
async{
let! z = f()
return test1 z
}
版本。 / p>
f
这当然是一个过于简单的例子。通常情况下,您有asyncs
取决于某些参数,并且只是将其拉出其上下文可能是不可能的。在这种情况下,我会尝试重构逻辑以适应它,而不会在原始代码上撒上asyncs
。收集运行let test () =
async {
let inputs = figureOutInputs()
let! results = doAsyncStuff inputs
return processResults results
}
,运行它们并将结果作为单独步骤处理所需的所有信息。
interface Expression {
int getValue();
}
class Constant implements Expression {
private int value;
public int getValue() {
return value;
}
}
class Operation implements Expression {
private Expression operand1;
private Operator operator;
private Expression operand2;
public int getValue() {
return operator.apply(operand1, operand2);
}
}
这样你可以限制传染扩散太多;)