如何决定ThreadPoolTask​​Executor池和队列大小?

Ant*_*lev 10 java spring multithreading threadpool

这可能是更一般的问题,关于如何决定线程池大小,但让我们ThreadPoolTaskExecutor在这种情况下使用Spring .我对池核心和最大大小以及队列容量进行了以下配置.我已经阅读有关所有这些配置的意思是-有一个很好的答案在这里.

    @SpringBootApplication
    @EnableAsync
    public class MySpringBootApp {

        public static void main(String[] args) {
            ApplicationContext ctx = SpringApplication.run(MySpringBootApp.class, args);
        }

        @Bean
        public TaskExecutor taskExecutor() {
            ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
            executor.setCorePoolSize(5);
            executor.setMaxPoolSize(10);
            executor.setQueueCapacity(25);
            return executor;
        }

    }
Run Code Online (Sandbox Code Playgroud)

以上数字对我来说是随机的,我想了解如何根据我的环境正确设置它们.我将概述以下约束:

  1. 该应用程序将在双核CPU盒上运行
  2. 执行者将完成一项通常需要1-2秒才能完成的任务.
  3. 通常我希望800/min的任务提交给我的遗嘱执行人,以2500/min的速度飙升
  4. 该任务将构造一些对象并对Google pubsub进行HTTP调用.

理想情况下,我想了解我需要考虑的其他约束,并基于它们对我的池和队列大小的合理配置.

Jer*_*and 13

它可能不是最准确的答案,但我会尝试:

一个简单的方法是要知道你的2核CPU只能同时在两个线程上工作.

如果您拥有相对现代的Intel CPU,并且已打开超线程(又称HT(TM),HTT(TM),SMT)(通过BIOS中的设置),您的操作系统将看到可用内核数量增加一倍CPU中的物理内核数量.

无论哪种方式,从Java来检测你可以使用多少个核心(或同时不抢占彼此的线程),只需要调用 int cores = Runtime.getRuntime().availableProcessors();

如果您尝试将您的应用程序视为Workshop(实际的):

  • 处理器将由员工代表.它是为产品增加价值的物理单位.
  • 任务将是一块原材料(加上一些说明清单)
  • 您的主题是一个桌面,员工可以在其上完成任务并开始工作.
  • 队列大小是传送带的长度,将原材料带到桌面.

因此,您的问题变成了" 如果员工数量不变,我怎样才能选择多少台桌子以及我的传送带能在我的工厂内停放多长时间? ".

对于多少桌子(线程)部分:

员工一次只能在一个办公桌上工作,每个办公桌只能有一名员工.因此,基本设置将至少具有与员工一样多的办公桌(以避免任何员工(处理器)被遗漏而没有任何工作可能性.

但是,根据您的活动,您可以为每位员工提供更多办公桌:

如果您的员工需要不断地将信件放入信封内,那么需要全程关注的操作(编程:分类收集,创建对象,递增计数器),拥有更多办公桌将无济于事,甚至可能是有害的,因为您的员工会必须有时改变办公桌(切换上下文,这需要一些时间),从而留下他们正在进行的工作,以使另一方面的工作进展.

但是,如果您的任务是制作陶器,并依赖您的员工等待粘土在烤箱中烹饪(了解如何访问外部资源,例如文件系统,Web服务等),您的员工可以负担得起模型粘土在另一张桌子上,稍后再回到第一张桌子上.

因此,只要您的任务具有足够大的活动工作/等待率(运行/等待),您就可以为每位员工提供更多办公桌.办公桌的数量是您的员工在等待时间内可以进行多少任务.

对于传送带(队列)尺寸部分:

队列大小表示在开始拒绝任何更多任务之前允许排队的项目数量(通过抛出异常),因此是您开始告诉"好的,我已经超额预订并且永远不会超过"的阈值能够遵守"

首先,我要说你的输送带需要安装在车间内.意味着集合应该足够小以防止内存不足错误(显然).

之后,它基于您的公司政策.假设每次客户订单(另一个服务调用您的API)时,任务都会添加到磁带上.如果来电者不在乎你花了多少时间来遵守和信任你,那么限制腰带的大小是没有意义的.

但是,如果你可以期待你的客户在等待他们的陶器一个月后生气,并让你同时或重新订购另一个陶器,假设第一个订单丢失,并且不会费心去检查第一个订单是否是已完成......第一个订单一无所获,您将无法获得付款,如果您的客户在您太慢遵守时再下订单,您将进入反馈循环,因为每个新订单都会减速整个过程.

因此,在这种情况下,你应该竖起一个告诉你的客户的标语"对不起,我们已超额预订,你现在不应该做任何新的订单,因为我们无法在可接受的时间范围内遵守".

然后,队列大小将是:完成任务的可接受时间范围/时间.

具体示例:如果您的客户端服务期望它提交的任务必须在不到100秒的时间内完成,并且知道每个任务需要1-2秒,那么您应该将队列限制为50-100个任务,因为一旦您有100个任务在队列中等待的任务,你很确定下一个任务将在不到100秒的时间内完成,从而拒绝任务以防止服务等待任何事情.