这可能是更一般的问题,关于如何决定线程池大小,但是让我们在这种情况下使用Spring ThreadPoolTaskExecutor
。我对池核心和最大大小以及队列容量进行了以下配置。我已经阅读了所有这些配置的含义 - 有一个很好的答案here。
@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;
}
}
以上数字对我来说是随机的,我想了解如何根据我的环境正确设置它们。我将概述以下约束:
理想情况下,我想了解我需要考虑的其他约束,并基于它们对我的池和队列大小的合理配置。
答案 0 :(得分:9)
这可能不是最准确的答案,但我会尝试:
一个简单的方法是要注意你的2核CPU只能同时在两个线程上工作。
如果您拥有相对现代的 Intel CPU,并且您拥有超线程(又名。 HT (TM), HTT (TM), SMT )打开(通过BIOS中的设置),您的操作系统将看到可用内核数量是CPU内物理内核数量的两倍。
无论哪种方式,从Java来检测您可以使用多少个核心(或同时不抢占彼此的线程),只需调用int cores = Runtime.getRuntime().availableProcessors();
如果您尝试将应用程序视为研讨会(实际的):
因此,您的问题变成了" 如果员工人数不变,我怎样才能选择多少台桌子以及我的传送带在工厂内的时间长度?"。
对于多少桌子(线程)部分:
员工一次只能在一个办公桌上工作,每个办公桌只能有一名员工。因此,基本设置是至少拥有与员工一样多的办公桌(以避免任何员工(处理器)被遗漏而无法工作。
但,根据您的活动,您可以为每位员工提供更多办公桌:
如果您的员工需要不断地将信件放在信封中,那么需要他们全力关注的操作(在编程中:排序集合,创建对象,增加计数器),拥有更多的办公桌就不会有。帮助,甚至可能是有害的,因为你的员工必须这样做 有时改变办公桌(切换上下文,这需要一些时间),从而留下他们正在处理的那个,以便在另一个上工作。
但是,如果您的任务是制作陶器,并依赖您的员工等待粘土在烤箱中烹饪(了解访问外部资源,例如文件系统,Web服务等),您的员工可以在另一张桌子上买模型粘土,然后再回到第一张桌子上。
因此,只要您的任务具有足够大的活动工作/等待率(正在运行/等待),您就可以为每位员工提供更多办公桌。办公桌的数量是您的员工在等待时间内可以完成多少任务。
对于传送带(队列)尺寸部分:
队列大小表示在开始拒绝任何更多任务之前允许排队的项目数量(通过抛出异常),因此是您开始告诉我的阈值,好吧,我'我已经超额预订,并且永远无法遵守#34;
首先,我要说你的输送带需要安装在车间内。这意味着该集合应该足够小以防止内存不足错误(显然)。
之后,它基于您的公司政策。让我们假设每次客户订单时都会将任务添加到磁带上(另一个服务调用您的API )。如果来电者并不关心您需要花多少时间来遵守并且对执行有足够的信任,那么限制腰带的尺寸是没有意义的。
但是,如果你可以期待你的客户在等待他们的陶器一个月后感到烦恼,并让你同时或重新订购另一个陶器,假设第一个订单丢失并且不会被打扰去检查如果第一个订单已经完成......第一个订单是无所事事的,您将无法获得付款,如果您的客户在您太慢而无法遵守的情况下再次下订单,您将进入在反馈循环中,因为每个新订单都会减慢整个过程。
因此,在这种情况下,你应该竖起一个标志告诉你的客户"对不起,我们已超额预订,你现在不应该做任何新订单,因为我们不会能够在可接受的时间范围内遵守#34;。
然后,队列大小为:可接受的时间范围 / 完成任务的时间。
具体示例:如果您的客户端服务期望它提交的任务必须在不到100秒内完成,并且知道每个任务需要1-2秒,那么您应该将队列限制为50-100个任务,因为一次你有100个任务在队列中等待,你很确定下一个任务不会在100秒内完成,从而拒绝任务以防止服务等待任何事情。