Vee*_*era 9 asynchronous playframework playframework-2.0
我正在使用Play framework 2.2作为我即将推出的Web应用程序之一.我已经以同步模式实现了我的控制器,有几个阻塞调用(主要是数据库).
例如,
public static Result index(){
User user = db.getUser(email); // blocking
User anotherUser = db.getUser(emailTwo); // blocking
...
user.sendEmail(); // call to a webservice, blocking.
return ok();
}
Run Code Online (Sandbox Code Playgroud)
因此,在优化代码的同时,决定利用Play的异步编程支持.通过文档,但这个想法对我来说仍然含糊不清,因为我对如何正确地将上述同步代码块转换为Async感到困惑.
所以,我提出了以下代码:
public static Promise<Result> index(){
return Promise.promise(
new Function0<Result>(){
public Result apply(){
User user = db.getUser(email); // blocking
User anotherUser = db.getUser(emailTwo); // blocking
...
user.sendEmail(); // call to a webservice, blocking.
return ok();
}
}
);
}
Run Code Online (Sandbox Code Playgroud)
所以,我只是将整个控制逻辑包装在一个promise块中.
play框架本质上是异步的,它允许创建完全非阻塞的代码.但是为了无阻塞 - 带来所有好处 - 你不能只是包装你的阻止代码并期待魔法发生......
在理想情况下,您的完整应用程序是以非阻塞方式编写的.如果这是不可能的(无论出于何种原因),您可能希望在Akka actor中或在返回的异步接口后面抽象阻塞代码scala.concurrent.Future.这样,您可以在专用的执行上下文中同时执行阻止代码,而不会影响其他操作.毕竟,让所有操作共享相同的ExecutionContext意味着它们共享相同的线程池.因此,阻止线程的Action可能会在CPU未充分利用的同时对其他执行纯CPU的操作产生巨大影响!
在您的情况下,您可能希望从最低级别开始.看起来数据库调用是阻塞的,所以首先重构这些.您需要为正在使用的数据库找到异步驱动程序,或者如果只有阻塞驱动程序可用,您应该在将来使用特定于DB的执行上下文(使用与DB ConnectionPool).
抽象异步接口背后的数据库调用的另一个好处是,如果在将来某个时候,您切换到非阻塞驱动程序,您只需更改接口的实现,而无需更改控制器!
在您的重新激活的控制器中,您可以处理这些未来并与它们一起工作(当它们完成时).您可以在此处找到有关与期货合作的更多信息
以下是执行非阻塞调用的控制器方法的简化示例,然后在视图中组合结果,同时发送异步电子邮件:
public static Promise<Result> index(){
scala.concurrent.Future<User> user = db.getUser(email); // non-blocking
scala.concurrent.Future<User> anotherUser = db.getUser(emailTwo); // non-blocking
List<scala.concurrent.Future<User>> listOfUserFutures = new ArrayList<>();
listOfUserFutures.add(user);
listOfUserFutures.add(anotherUser);
final ExecutionContext dbExecutionContext = Akka.system().dispatchers().lookup("dbExecutionContext");
scala.concurrent.Future<Iterable<User>> futureListOfUsers = akka.dispatch.Futures.sequence(listOfUserFutures, dbExecutionContext);
final ExecutionContext mailExecutionContext = Akka.system().dispatchers().lookup("mailExecutionContext");
user.andThen(new OnComplete<User>() {
public void onComplete(Throwable failure, User user) {
user.sendEmail(); // call to a webservice, non-blocking.
}
}, mailExecutionContext);
return Promise.wrap(futureListOfUsers.flatMap(new Mapper<Iterable<User>, Future<Result>>() {
public Future<Result> apply(final Iterable<User> users) {
return Futures.future(new Callable<Result>() {
public Result call() {
return ok(...);
}
}, Akka.system().dispatcher());
}
}, ec));
}
Run Code Online (Sandbox Code Playgroud)
如果您没有任何不阻塞的东西,那么可能没有理由让您的控制器异步。这是 Play 的创建者之一写的关于此的好博客:http ://sadache.tumblr.com/post/42351000773/async-reactive-nonblocking-threads-futures-executioncont
| 归档时间: |
|
| 查看次数: |
3076 次 |
| 最近记录: |