Concurrency javaee环境中的并发性 球门

Concurrency javaee环境中的并发性 球门,concurrency,jakarta-ee,httprequest,actor,Concurrency,Jakarta Ee,Httprequest,Actor,我的目标是更好地理解JavaEE环境中的并发性,以及如何更好地使用它 一般问题 让我们以典型的servlet容器tomcat为例。对于每个请求,它使用一个线程来处理它。线程池的配置使其池中最多可以有80个线程。让我们再来看一个简单的webapp——它在每个请求期间进行一些处理和DB通信 在高峰期,我可以看到80个并行运行的线程+几个其他的基础结构线程。我们还假设我在'm1.large'EC2实例中运行它 我不认为所有这些线程都能在这个硬件上并行运行。所以现在调度器应该决定如何更好地在它们之间分配

我的目标是更好地理解JavaEE环境中的并发性,以及如何更好地使用它

一般问题 让我们以典型的servlet容器tomcat为例。对于每个请求,它使用一个线程来处理它。线程池的配置使其池中最多可以有80个线程。让我们再来看一个简单的webapp——它在每个请求期间进行一些处理和DB通信

在高峰期,我可以看到80个并行运行的线程+几个其他的基础结构线程。我们还假设我在'm1.large'EC2实例中运行它

我不认为所有这些线程都能在这个硬件上并行运行。所以现在调度器应该决定如何更好地在它们之间分配CPU时间。所以问题是-在这种情况下,调度程序开销有多大?如何在线程数量和处理速度之间找到适当的平衡

演员比较 在4核CPU上有80多个线程对我来说并不健康。特别是如果它们中的大多数被某种IO DB、文件系统、套接字阻塞,它们只会消耗宝贵的资源。如果我们将请求从线程中分离出来,并且只有合理数量的线程(例如8个线程),并且只向它们发送处理任务,会怎么样。当然,在这种情况下IO也应该是非阻塞的,这样当我需要的某些数据可用时,我会接收事件,如果我有一些结果,我会发送事件

据我所知,演员模型就是这样。至少在Akka和Scala中,演员不受线程的约束。所以我有合理的线程池和一堆参与者,他们的邮箱包含处理任务

现在的问题是-在性能、调度程序开销和资源RAM、CPU消耗方面,actor模型与传统的每请求线程模型相比如何

自定义线程 我有一些请求,只有几个需要花费太多时间来处理。我优化了代码和所有算法,添加了缓存,但仍然需要太多时间。但我明白了,这个算法可以并行化。它很自然地符合参与者模型——我只是将我的大任务分成几个任务,然后在需要时以某种方式聚合结果。但在每请求线程模型中,我需要生成自己的线程或创建小型线程池。据我所知,不建议在JavaEE环境中使用这种方法。而且,从我的观点来看,它并不适合每请求线程模型。问题出现了:我的线程池大小应该有多大?即使我会使它在硬件方面合理,我仍然有servlet容器管理的这组线程。线程管理变得分散,变得疯狂

所以我的问题是——在每个请求线程模型中,处理这些情况的最佳方法是什么

在4核CPU上有80多个线程对我来说并不健康。特别是如果它们中的大多数被某种IO DB、文件系统、套接字阻塞,它们只会消耗宝贵的资源

错。正是在这种情况下,处理器可以处理比单个内核数量多得多的线程,因为任何时间点的大多数线程都被阻塞等待I/O。公平地说,上下文切换需要时间,但与文件/网络/DB延迟相比,这种开销通常是不相关的

线程数应等于或略大于处理器内核数的经验法则仅适用于计算密集型任务,此时内核大部分时间处于繁忙状态

我有一些请求,只有几个需要花费太多时间来处理。我优化了代码和所有算法,添加了缓存,但仍然需要太多时间。但我明白了,这个算法可以并行化。它很自然地符合参与者模型——我只是将我的大任务分成几个任务,然后在需要时以某种方式聚合结果。但在每请求线程模型中,我需要生成自己的线程或创建小型线程池。据我所知,不建议在JavaEE环境中使用这种方法

我从未听说过这一点,但我并不声称自己是终极JavaEE专家。IMHO使用例如a并行执行与单个请求相关的任务没有什么错。请注意,这些线程不是请求处理线程,因此它们不会直接干扰EJB容器使用的线程池。当然,除了它们竞争相同的资源之外,它们可能会在不小心的设置中减慢或完全停止其他请求处理线程

在每个请求的线程模型中,处理这些情况的最佳方法是什么

最后,您无法逃避测量并发性能和微调线程池的大小以及您自己特定环境的其他参数

在4核CPU上有80多个线程对我来说并不健康。特别是如果它们中的大多数被某种IO DB、文件系统、套接字阻塞,它们只会消耗宝贵的资源

错。正是在这种情况下,处理器可以处理许多问题 线程数大于单个内核的数量,因为任何时间点的大多数线程都被阻塞等待I/O。公平地说,上下文切换需要时间,但与文件/网络/DB延迟相比,这种开销通常无关紧要

线程数应等于或略大于处理器内核数的经验法则仅适用于计算密集型任务,此时内核大部分时间处于繁忙状态

我有一些请求,只有几个需要花费太多时间来处理。我优化了代码和所有算法,添加了缓存,但仍然需要太多时间。但我明白了,这个算法可以并行化。它很自然地符合参与者模型——我只是将我的大任务分成几个任务,然后在需要时以某种方式聚合结果。但在每请求线程模型中,我需要生成自己的线程或创建小型线程池。据我所知,不建议在JavaEE环境中使用这种方法

我从未听说过这一点,但我并不声称自己是终极JavaEE专家。IMHO使用例如a并行执行与单个请求相关的任务没有什么错。请注意,这些线程不是请求处理线程,因此它们不会直接干扰EJB容器使用的线程池。当然,除了它们竞争相同的资源之外,它们可能会在不小心的设置中减慢或完全停止其他请求处理线程

在每个请求的线程模型中,处理这些情况的最佳方法是什么


最后,您无法逃避测量并发性能和微调线程池的大小以及针对您自己特定环境的其他参数。

Java EE的整个要点是将常见的体系结构问题(如安全性、状态、,和并发性集成到框架中,并允许您提供业务逻辑或数据映射以及连接它们的连接。因此,JavaEE故意隐藏了框架中读/写可变状态的令人讨厌的并发锁定

这种方法允许更广泛的开发人员成功地编写正确的应用程序。不过,一个必要的副作用是,这些抽象会产生开销并消除控制。如果您知道自己在做什么,并且能够在框架中做出不可能的选择,那么这既有利于简化策略,也有利于将策略编码为策略而不是编码

在一个生产箱上有80个线程本身并不坏。大多数将被阻止或等待I/O,这是正常的。有一个可调的线程池来执行实际的计算,JavaEE将为您提供外部钩子来调优这些旋钮


演员是另一种模式。它们还允许您在参与者主体中编写代码孤岛,以避免锁定以修改状态。您可以将您的参与者编写为无状态的,以捕获递归函数调用参数中的状态,或者在参与者实例中完全隐藏您的状态,因此状态仅限于react样式的参与者。您可能仍然需要显式锁定数据访问,以确保运行参与者的下一个线程的可见性

我不能说其中一个更好。我认为有足够的证据证明这两种模型都可以用来编写安全、高吞吐量的系统。为了使这两种方法都能很好地发挥作用,你需要认真思考你的问题,并构建能够隔离部分状态和每种状态的计算的应用程序。对于能够很好地理解数据并具有很高的并行性潜力的代码,我认为JavaEE之外的模型非常有意义

通常,调整计算绑定线程池大小的经验法则是,它们应该大约等于内核的N+2。许多框架会自动调整大小。您可以使用Runtime.getRuntime.availableProcessor获得N。如果您的问题以分治式算法分解,并且数据项的数量很大,我强烈建议您检查fork/join,它现在可以作为一个单独的库使用,并且将成为Java 7的一部分

至于如何管理这一点,您不应该在Java EE中产生线程,因为它们希望控制这些线程,但您可以研究通过消息队列向数据处理线程池发送请求,并通过返回消息处理该请求。这当然有点笨拙地适合JavaEE模型


我这里有一些参与者、fork/join和一些其他并发模型,您可能会对此感兴趣:

JavaEE的全部要点是将常见的架构问题(如安全性、状态和并发性)放入框架中,并允许您提供一些业务逻辑或数据映射以及连接它们的连线。因此,JavaEE故意隐藏了框架中读/写可变状态的令人讨厌的并发锁定

这种方法允许更广泛的开发人员成功地编写正确的应用程序。必要的 ide的效果是,这些抽象产生了开销并消除了控制。如果您知道自己在做什么,并且能够在框架中做出不可能的选择,那么这既有利于简化策略,也有利于将策略编码为策略而不是编码

在一个生产箱上有80个线程本身并不坏。大多数将被阻止或等待I/O,这是正常的。有一个可调的线程池来执行实际的计算,JavaEE将为您提供外部钩子来调优这些旋钮


演员是另一种模式。它们还允许您在参与者主体中编写代码孤岛,以避免锁定以修改状态。您可以将您的参与者编写为无状态的,以捕获递归函数调用参数中的状态,或者在参与者实例中完全隐藏您的状态,因此状态仅限于react样式的参与者。您可能仍然需要显式锁定数据访问,以确保运行参与者的下一个线程的可见性

我不能说其中一个更好。我认为有足够的证据证明这两种模型都可以用来编写安全、高吞吐量的系统。为了使这两种方法都能很好地发挥作用,你需要认真思考你的问题,并构建能够隔离部分状态和每种状态的计算的应用程序。对于能够很好地理解数据并具有很高的并行性潜力的代码,我认为JavaEE之外的模型非常有意义

通常,调整计算绑定线程池大小的经验法则是,它们应该大约等于内核的N+2。许多框架会自动调整大小。您可以使用Runtime.getRuntime.availableProcessor获得N。如果您的问题以分治式算法分解,并且数据项的数量很大,我强烈建议您检查fork/join,它现在可以作为一个单独的库使用,并且将成为Java 7的一部分

至于如何管理这一点,您不应该在Java EE中产生线程,因为它们希望控制这些线程,但您可以研究通过消息队列向数据处理线程池发送请求,并通过返回消息处理该请求。这当然有点笨拙地适合JavaEE模型


我这里有一些actor、fork/join和其他一些并发模型,您可能会对此感兴趣:

对于react样式的actor,您可能仍然需要显式地锁定数据访问,以确保运行actor的下一个线程的可见性@维克多:嗯,你会知道的,所以我相信你!我设想了一个Scala参与者拥有私有可变状态的情况。在这种情况下,必须有人确保JVM级别的可见性障碍,对吗?谁?@Alex通常只需将消息执行包装在一个同步块中,因为这是单个入口点,所以它提供了所需的同步/flush@Viktor:嗯,使用Synchronized块正是我所说的显式锁定数据访问的意思…@Alex:我将您解释为react样式的参与者,您可能仍然需要作为框架的用户而不是框架的实现者显式锁定数据访问。因此,为了澄清,用户不需要对其执行任何显式锁定,该锁定由框架隐式提供,由实现者设计。对于react样式的参与者,您可能仍然需要显式锁定数据访问,以确保运行参与者的下一个线程的可见性@维克多:嗯,你会知道的,所以我相信你!我设想了一个Scala参与者拥有私有可变状态的情况。在这种情况下,必须有人确保JVM级别的可见性障碍,对吗?谁?@Alex通常只需将消息执行包装在一个同步块中,因为这是单个入口点,所以它提供了所需的同步/flush@Viktor:嗯,使用Synchronized块正是我所说的显式锁定数据访问的意思…@Alex:我将您解释为react样式的参与者,您可能仍然需要作为框架的用户而不是框架的实现者显式锁定数据访问。因此,为了澄清这一点,用户不需要对其进行任何显式锁定,锁定是由框架隐式提供的,正如实现者所设计的那样。