非阻塞风格有什么好处?
What are benefits of non-blocking style?
我正在尝试了解非阻塞编程(以及项目反应器等框架)的核心原则。主要思想是让 "thread pool" 具有确定数量的线程(执行程序)和在那里执行的任务。我们不应该有任何阻塞的线程。在 "user code" 中,我们只是 运行 要执行的东西并留下回调(如何处理结果)。 out"user"线程没有阻塞,对吧。但是,如果我的任务取决于某些 jdbc 查询怎么办。我的任务会请求这个查询,然后会被阻塞等待结果,对吗?所以,这个线程被阻塞了。
但是我们避免创建线程(这很昂贵)。是这种风格的核心优势吗?
如果我的线程池由2个执行器组成,并且都被阻塞等待某事,其他任务将不会被执行,对吧?如何避免?创建超过 2 个线程?
线程是相对昂贵的系统资源。例如,每个线程都需要用于调用堆栈的内存。大小取决于操作系统,但通常约为 1 或 2 MB。这意味着启动数千个线程不是一个好主意 - 仅在 1000 个线程的调用堆栈上就会浪费 1 或 2 GB 内存。
因此,为了更高效地做事,您需要限制线程数量,例如使用线程池来处理工作。线程池可以管理正在使用的线程数。
但是,假设您有一个包含 10 个线程的线程池,然后有 10 个请求进入。您的每个线程都将被保留来处理一个请求。当他们很忙时,您无法处理请求 #11,因为没有空闲线程。当您使用阻塞 I/O 时,即使您所有的 10 个线程都没有做任何事情(等待 I/O 完成),请求 #11 也无法处理...
当您使用非阻塞 I/O 时,线程永远不需要等待 I/O - 所以当处理请求 #3 被暂停时,因为它需要 [=27= 的结果] 操作,正在处理它的线程可以暂时切换到处理其他请求。
因此,使用非阻塞 I/O,您永远不会有等待线程,您可以更有效地使用系统资源。
这仅在您从系统的前端到后端使用非阻塞 I/O 时才有效。如果在后端使用 JDBC,这是一个阻塞 API,那么您将失去非阻塞 I/O.
的全部好处
因此,如果您在后端有一个数据库,那么如果您有一个支持非阻塞的数据库 I/O,这种方法效果最好。一些像 MongoDB 这样的 NoSQL 数据库支持这个,对于一些关系数据库,有特殊的驱动程序/ APIs 可以支持这个。在那种情况下你不会使用 JDBC,因为 JDBC 是一个固有的阻塞 API.
Oracle 正在为关系数据库开发一个新的 API,暂时称为
ADBA 这将允许您使用关系数据库执行非阻塞/异步 I/O 但它还没有准备好。
Project Reactor 是 Reactive Streams 规范的一个实现。可以在 ReactiveManifest 找到规范概述。它不仅仅是创建一组线程并让它们完成它们的工作,它是框架或运行时(在本例中为 ProjectReactor),它将以一种可能表现得像非阻塞的方式组织您的代码。此外,整个系统实现必须采用这种方式,否则您将无法从反应流中受益。
If my thread pool consists of 2 executors and both are blocked waiting for something, other tasks will not be executed, right? How to avoid it? Create more than 2 threads?
这个问题的答案是肯定的,也不是。框架可能不会创建线程。由于代码将在线程之间交错,由于非阻塞系统是事件驱动的,包括低级操作(例如,libuv I/O),线程没有必要等待一个完成I/O 操作。同时,线程将执行一些有意义的事情。任务完成将收到通知,相关代码可以由任何可用线程执行。这种系统的目标是以有限的资源(线程)充分利用 CPU。
摘自 http://www.reactive-streams.org。
Reactive Streams 的主要目标是管理跨异步边界的流数据交换——想想将元素传递到另一个线程或线程池——同时确保接收方不会被迫缓冲任意数量的数据数据。换句话说,背压是这个模型的一个组成部分,以便允许在线程之间进行调解的队列被限制。如果背压通信是同步的,则异步处理的好处将被抵消(另请参阅 Reactive Manifesto),因此必须注意强制 Reactive Streams 实现的所有方面的完全非阻塞和异步行为。
Reactor 框架强制并帮助您从头开始构建完全无阻塞的系统。
我正在尝试了解非阻塞编程(以及项目反应器等框架)的核心原则。主要思想是让 "thread pool" 具有确定数量的线程(执行程序)和在那里执行的任务。我们不应该有任何阻塞的线程。在 "user code" 中,我们只是 运行 要执行的东西并留下回调(如何处理结果)。 out"user"线程没有阻塞,对吧。但是,如果我的任务取决于某些 jdbc 查询怎么办。我的任务会请求这个查询,然后会被阻塞等待结果,对吗?所以,这个线程被阻塞了。
但是我们避免创建线程(这很昂贵)。是这种风格的核心优势吗?
如果我的线程池由2个执行器组成,并且都被阻塞等待某事,其他任务将不会被执行,对吧?如何避免?创建超过 2 个线程?
线程是相对昂贵的系统资源。例如,每个线程都需要用于调用堆栈的内存。大小取决于操作系统,但通常约为 1 或 2 MB。这意味着启动数千个线程不是一个好主意 - 仅在 1000 个线程的调用堆栈上就会浪费 1 或 2 GB 内存。
因此,为了更高效地做事,您需要限制线程数量,例如使用线程池来处理工作。线程池可以管理正在使用的线程数。
但是,假设您有一个包含 10 个线程的线程池,然后有 10 个请求进入。您的每个线程都将被保留来处理一个请求。当他们很忙时,您无法处理请求 #11,因为没有空闲线程。当您使用阻塞 I/O 时,即使您所有的 10 个线程都没有做任何事情(等待 I/O 完成),请求 #11 也无法处理...
当您使用非阻塞 I/O 时,线程永远不需要等待 I/O - 所以当处理请求 #3 被暂停时,因为它需要 [=27= 的结果] 操作,正在处理它的线程可以暂时切换到处理其他请求。
因此,使用非阻塞 I/O,您永远不会有等待线程,您可以更有效地使用系统资源。
这仅在您从系统的前端到后端使用非阻塞 I/O 时才有效。如果在后端使用 JDBC,这是一个阻塞 API,那么您将失去非阻塞 I/O.
的全部好处因此,如果您在后端有一个数据库,那么如果您有一个支持非阻塞的数据库 I/O,这种方法效果最好。一些像 MongoDB 这样的 NoSQL 数据库支持这个,对于一些关系数据库,有特殊的驱动程序/ APIs 可以支持这个。在那种情况下你不会使用 JDBC,因为 JDBC 是一个固有的阻塞 API.
Oracle 正在为关系数据库开发一个新的 API,暂时称为 ADBA 这将允许您使用关系数据库执行非阻塞/异步 I/O 但它还没有准备好。
Project Reactor 是 Reactive Streams 规范的一个实现。可以在 ReactiveManifest 找到规范概述。它不仅仅是创建一组线程并让它们完成它们的工作,它是框架或运行时(在本例中为 ProjectReactor),它将以一种可能表现得像非阻塞的方式组织您的代码。此外,整个系统实现必须采用这种方式,否则您将无法从反应流中受益。
If my thread pool consists of 2 executors and both are blocked waiting for something, other tasks will not be executed, right? How to avoid it? Create more than 2 threads?
这个问题的答案是肯定的,也不是。框架可能不会创建线程。由于代码将在线程之间交错,由于非阻塞系统是事件驱动的,包括低级操作(例如,libuv I/O),线程没有必要等待一个完成I/O 操作。同时,线程将执行一些有意义的事情。任务完成将收到通知,相关代码可以由任何可用线程执行。这种系统的目标是以有限的资源(线程)充分利用 CPU。
摘自 http://www.reactive-streams.org。 Reactive Streams 的主要目标是管理跨异步边界的流数据交换——想想将元素传递到另一个线程或线程池——同时确保接收方不会被迫缓冲任意数量的数据数据。换句话说,背压是这个模型的一个组成部分,以便允许在线程之间进行调解的队列被限制。如果背压通信是同步的,则异步处理的好处将被抵消(另请参阅 Reactive Manifesto),因此必须注意强制 Reactive Streams 实现的所有方面的完全非阻塞和异步行为。
Reactor 框架强制并帮助您从头开始构建完全无阻塞的系统。