一些Play Framework开发人员said“永远不会在Promise上调用get(),因为它可能会导致死锁。”好。
假设我的遗留代码需要Bar
(而不是F.Promise<Bar>
)并在下面调用apply(Foo foo)
才能获得它。在apply
内,我想做一些并发的webservice调用,等待响应,然后使用它们来制作Bar
。如果不调用futureBar.get()
,我怎么能这样做,再次假设不能选择返回F.Promise<Bar>
?
public class Func implements F.Function<Foo,Bar> {
@Override
public Bar apply(Foo foo) throws Throwable {
F.Promise<WS.Response> response1 = WS.url("http://google.com").get();
F.Promise<WS.Response> response2 = WS.url("http://yahoo.com").get();
F.Promise<List<WS.Response>> responses = F.Promise.sequence(response1, response2);
F.Promise<Bar> futureBar = responses.map(new F.Function<List<WS.Response>, Bar>() {
@Override
public Bar apply(List<WS.Response> o) throws Throwable {
//some code;
return bar;
}
});
//How can I return Bar without calling get?
}
}
答案 0 :(得分:1)
(我从未使用过来自Java的Akka,所以不要完全理解你的代码细节,但我希望我能理解你的问题)
简短的回答:你无法获得Bar。并且你永远不应该调用.get,因为它要么杀死使用Futures / Promises(在最好的情况下)的所有优点,要么就像已经提到的那样导致死锁并杀死所有东西(在最坏的情况下)。一旦你在Future [ - ]中有东西,它总是留在未来[ - ],就没有办法了。如果您有遗留代码执行此操作:
bar = Func.apply(foo);
doSomethingWithBar(bar)
你突然发现你的Func不再同步(不立即返回),而是异步(发出一堆长请求),你必须接受你的新异步版本的Func不能和' ;'
所以你必须重新编程';'
当然,你不是自己动手,因为你已经有了Future [ - ] monad,所以你只需要替换旧的';'由新的';'即map / flatMap,取决于你的doSomethingWithBar是否同步:
Func.apply(foo).map{ bar =>
doSomethingWithBar(bar)
}
一般来说,如果你之前有类似的东西:
y = asynch_func1(x);
z = asynch_func2(x, y);
w = synch_func3(x, y, z);
v = asynch_func4(x, y, z, w);
print(v)
突然发现你的函数asynch_func1,asynch_func2,asynch_func4现在是异步的并且需要很长时间才能完成(虽然synch_func3保持同步,就像例子一样),你把它重写为:
asynch_func1(x).flatMap{ y =>
asynch_func2(x, y).map{ z =>
synch_func3(x,y,z).flatMap{ w =>
v = asynch_func4(x, y, z, w)
print(v)
}
}
}
我想它会看起来非常可怕(没有理解和Java语法......),但只要你有概念清晰度和理解你只是用map / flatMap替换分号,你应该是能够非常快速地调整遗留代码,而且(太)头痛。
我希望我已经回答了正确的问题。
答案 1 :(得分:1)
不是返回Bar
,而是返回F.Promise<Bar>
。
public class Func implements F.Function<Foo,F.Promise<Bar>> {
@Override
public F.Promise<Bar> apply(Foo foo) throws Throwable {
F.Promise<WS.Response> response1 = WS.url("http://google.com").get();
F.Promise<WS.Response> response2 = WS.url("http://yahoo.com").get();
F.Promise<List<WS.Response>> responses = F.Promise.sequence(response1, response2);
F.Promise<Bar> futureBar = responses.map(new F.Function<List<WS.Response>, Bar>() {
@Override
public Bar apply(List<WS.Response> o) throws Throwable {
//some code;
return bar;
}
});
return futureBar;
}
}
从那里开始,您使用Bar
,使用Promise
,map
和flatMap
在filter
内操作,如Javadoc所述:{{3 }}
异步工作时,您习惯于在将来的环境中处理代码,这就是保持代码异步的方法。
在Scala中,你会这样做:
def apply(foo: Foo): Future[Bar] = {
for {
response1 <- WS.url("http://google.com").get
response2 <- WS.url("http://yahoo.com").get
} yield {
// some code
bar
}
}