在Play 2.1中处理阻止操作

时间:2014-01-17 06:55:19

标签: java asynchronous playframework akka actor

我正在尝试创建一种在Play中以特定方式处理阻止操作的方法。首先,我描述了我的目标是什么,我到目前为止所管理的是什么。如果我走在正确的轨道上,你能告诉我 - 如果是的话,你能帮我理解如何完成代码吗?如果不是正确的方法,你可以建议一个更好的选择吗? 非常感谢你的帮助

目的: 希望将所有阻塞操作发送到一个线程,以便异步处理单独的线程。进入的新请求不会占用更多线程,而是将它们放入队列(或任何类似的)中以由单个线程处理。对于由额外线程异步处理的每个项目,必须收集一些文本并将其返回给浏览器。

因此,在阅读了docs和SO问题之后,似乎必须使用actor。我喜欢演员的概念,但之前从未使用过它们,所以我还在学习。这就是我所拥有的:

    package models;

    import java.io.*;
    import play.mvc.*;
    import play.libs.*;
    import play.libs.F.*;
    import akka.actor.*;

    public class ActorTest extends UntypedActor {
        static BufferedReader reader = new BufferedReader(new InputStreamReader(
                System.in));

        @Override
        public void onReceive(Object message) throws Exception {
            if (message instanceof String) {
                getSender().tell(
                        "You sent me " + ((String) message)
                                + " and the consol replied with "
                                + reader.readLine(), getSelf());
            } else
                unhandled(message);
        }

    }

正如您所看到的,阻塞操作是readLine() - 只是一种测试方法。

这是怎么做的?如果是这样,我假设从控制器,我有些如何创建异步结果或使用promises的东西。 [ Handling asynchronous results ]。

情侣问题,如何向演员发送消息并获得回复?我的意思是我可以通过tel()调用获得结果吗? 我如何确保更多的线程不被占用并且所有操作都进入队列 - 或者这是否已由演员处理?

请您提供可以执行此操作的示例控制器操作吗?

非常感谢您的帮助。

PS FYI我对这一切都很陌生,所以为了进入这个阶段,我发现这些文档很有用 - Akka演员页面,当然还有一些关于演员的维基页面。

[编辑] 对不起,我说单线程,但它可能是一个线程池 - 只要只使用分配的线程/线程池来处理阻塞而不是任何其他线程。

1 个答案:

答案 0 :(得分:2)

您可以使用ask(而不是tell)向Akka演员发送消息。它将返回一个Future,然后您可以映射到Promise<Result>

但是,如果你不需要,你根本不需要使用Akka。您可以简单地使用Futures / Promises在后台运行阻止操作。

在任何一种方法中,您最终都会得到一个Future,您可以在将来完成请求。

在Play 2.2.x中使用Promise的示例

...
import play.libs.F.*;

public static Promise<Result> index() {
  Promise<Integer> promiseOfInt = Promise.promise(
      new Function0<Integer>() {
        public Integer apply() {
          // long-running operation (will run in separate thread)
          return 42;
        }
      });

  return promiseOfInt.map(
      new Function<Integer, Result>() {
        public Result apply(Integer i) {
          // 'i' is the result after Promise is complete
          return ok("Got result: " + i);
        }
      });
}

如果您使用的是Akka,则需要将从Future返回的ask转换为Play Promise,如下所示:

public static Promise<Result> index() {
    ActorRef myActor = Akka.system().actorFor("user/my-actor");

    return Promise.wrap(ask(myActor, "hello", 1000)).map(
        new Function<Object, Result>() {
            public Result apply(Object response) {
                return ok(response.toString());
            }
        });
}

在Play 2.1.x中使用Promise的示例

...
import play.libs.F.*;

public static Result index() {
  Promise<Integer> promiseOfInt = play.libs.Akka.future(
      new Callable<Integer>() {
        public Integer call() {
          // long-running operation (will run in separate thread)
          return 42;
        }
      });
  return async(
      promiseOfInt.map(
        new Function<Integer,Result>() {
          public Result apply(Integer i) {
            // 'i' is the result after Promise is complete
            return ok("Got result: " + i);
          }
        }));
}

如果您使用的是Akka,则需要将从Future返回的ask转换为Play Promise,如下所示:

public static Result index() {
  ActorRef myActor = Akka.system().actorFor("user/my-actor");

  return async(
    Akka.asPromise(ask(myActor,"hello", 1000)).map(
      new Function<Object,Result>() {
        public Result apply(Object response) {
          return ok(response.toString());
        }
      }
    )
  );
}