我发现这篇文章解释了非阻塞IO Play框架:https://engineering.linkedin.com/play/play-framework-async-io-without-thread-pool-and-callback-hell
该文章中的代码示例
object ProxyController extends Controller {
def proxy = Action {
val responseFuture: Future[Response] = WS.url("http://example.com").get()
Logger.info("Before map")
val resultFuture: Future[Result] = responseFuture.map { resp =>
Logger.info("Within map")
// Create a Result that uses the http status, body, and content-type
// from the example.com Response
Status(resp.status)(resp.body).as(resp.ahcResponse.getContentType)
}
Logger.info("After map")
Async(resultFuture)
}
该文章的解释:
引擎盖下,Play使用一个大小为每个CPU一个线程的线程池 核心。其中一个稀缺线程T1执行代理操作, 从上到下遍历代码,除了内容 传递给map方法的函数,因为它依赖于a 尚未完成的非阻塞I / O调用。一旦T1返回 AsyncResult,它继续处理其他请求。 后来的时候 来自example.com的响应终于可用,另一个线程T2 (可能与T1相同或不同)执行传递的函数 到地图方法。任何线程都没有被阻止 等待example.com的回复。
我不明白该段中突出显示的内容。 T1已返回线程池,应用程序如何跟踪并从example.com接收响应,然后提交线程T2以执行map函数。
请有人解释一下。
答案 0 :(得分:2)
其中一个稀缺线程T1执行代理操作,从上到下运行代码,除了传递给map方法的函数内容,因为这取决于非阻塞I / O调用尚未完成。
此时已创建一个名为 future 的对象。
一旦T1返回AsyncResult,它就会继续处理其他请求。
当某些IO进入时,未来将在内存中等待实现。同时线程T1可以处理其他请求。
稍后,当example.com的响应最终可用时,
当响应可用时,这将调用一些内部Play代码,该代码读取响应并更改 future 的状态以赋予其值。在未来获得价值的那一刻,它会安排其 map 代码运行。这将在线程池中的某个线程中运行,例如T2。
另一个线程T2(可能与T1相同或不同)执行传递给map方法的函数。
任何一个线程都没有阻止等待来自example.com的响应。
Play不是通过阻塞线程来等待IO,而是秘密地注册了一个回调,这样当IO可用时它将实现未来。当未来完成时,它会自动调用应用程序代码的下一部分。这意味着应用程序代码可以等待(不使用线程),直到IO可用。