非阻塞样式的好处是什么?

时间:2018-11-22 11:39:08

标签: java multithreading asynchronous nonblocking project-reactor

我正在尝试理解非阻塞编程的核心原理(以及项目反应堆之类的框架)。主要思想是使“线程池”具有确定数量的线程(执行程序)和在此执行的任务。我们不应有任何阻塞的线程。在“用户代码”中,我们只运行一些要执行的内容并留下回调(与结果有关)。出“用户”线程未被阻止,对。但是,如果我的任务取决于某些jdbc查询,该怎么办?我的任务将请求此查询,然后将被阻止等待结果,对吗?因此,该线程被阻止了。

但是我们避免创建线程(这很昂贵)。这是这种风格的核心优势吗?

如果我的线程池由2个执行器组成,并且都被阻止等待,则其他任务将不会执行,对吗?如何避免呢?创建两个以上的线程?

2 个答案:

答案 0 :(得分:6)

线程是相对昂贵的系统资源。例如,每个线程都需要用于调用堆栈的内存。多少取决于操作系统,但是通常大约为1或2 MB。这意味着启动数千个线程不是一个好主意-仅在1000个线程的调用堆栈上浪费1或2 GB内存。

因此,为了更有效地执行操作,您想限制线程数,例如使用线程池来处理工作。线程池使管理正在使用的线程数成为可能。

但是,假设您有一个包含10个线程的线程池,然后有10个请求进入。每个线程将被保留以处理一个请求。当他们忙碌时,您将无法处理请求#11,因为没有可用的线程。当您使用阻塞I / O时,即使所有10个线程都没有执行任何操作(等待I / O完成),也无法处理请求#11 ...

当使用非阻塞I / O时,线程将永远不需要等待I / O-因此,当处理请求#3挂起时,因为它需要I / O操作的结果,因此正在处理的线程它可以暂时切换为处理其他请求。

因此,通过非阻塞I / O,您永远不会有等待线程,并且可以更有效地使用系统资源。

仅在从系统正面到背面使用非阻塞I / O时,此方法才有效。如果在后端使用的是JDBC(即阻塞API),那么您将失去非阻塞I / O的全部好处。

因此,如果您在后端有一个数据库,那么如果您有一个支持非阻塞I / O的数据库,则这种方法最有效。一些NoSQL数据库(如MongoDB)支持此功能,而对于某些关系数据库,则提供支持此功能的特殊驱动程序/ API。在这种情况下,您将不会使用JDBC,因为JDBC是一个固有的阻塞API。

Oracle正在为关系数据库开发一个新的API,临时称为  ADBA,它允许您对关系数据库执行非阻塞/异步I / O,但尚未准备就绪。

答案 1 :(得分:1)

Project Reactor是Reactive Streams规范的实现。规格概述可在ReactiveManifest中找到。这不只是创建一组线程并让它们完成工作,而是框架或运行时(在本例中为ProjectReactor)将以某种方式组织您的代码,以使其表现为非阻塞。另外,整个系统的实现必须采用这种方式,否则您将无法从反应式流中受益。

  

如果我的线程池由2个执行器组成,并且都被阻止等待,则其他任务将不会执行,对吗?如何避免呢?创建两个以上的线程?

答案是肯定的,不是。该框架可能未创建线程。由于代码将在线程之间交错,因此非阻塞系统是由事件驱动的,包括低级操作(例如,libuv I / O),因此线程不必等待I / O的完成O操作。同时,线程将执行有意义的事情。任务的完成将被通知,并且相关代码可以由任何可用线程执行。这种系统的目标是在有限的资源(线程)下充分利用CPU。

取自http://www.reactive-streams.org响应式流的主要目标是管理跨异步边界的流数据交换(请考虑将元素传递到另一个线程或线程池),同时确保不强制接收方缓冲任意数量的数据。换句话说,背压是此模型不可或缺的一部分,以使在线程之间进行中介的队列受到限制。如果背压的通信是同步的,则异步处理的好处将被抵消(另请参见“响应式宣言”),因此必须谨慎地对响应式流实现的所有方面强制要求完全无阻塞和异步行为。 em>

这是Reactor框架,可以强制并帮助您从头开始构建完全无阻塞的系统。