更新 :这个答案多年来得到了一些投票,所以我为那些没有时间阅读我奇怪的比喻的人添加了一个缩短的版本:
TL;DR 答案 :
实际的约束是(逻辑)CPU 内核只能同时运行单个线程。因此:
-
核心数 : CPU 的逻辑核心数 * 1/(ratio_of_time_your_thread_is_runnable_when_doing_your_task)
因此,如果您的计算机上有 8 个逻辑内核,则可以安全地将 8 个线程放入 threadPool 中(好吧,请记住排除可能使用的其他线程)。然后你需要问问自己是否可以投入更多 :你需要对你打算在线程池上运行的任务类型进行基准测试 :如果你注意到线程平均只运行50%的时间,这意味着你的CPU可以自由地在另一个线程上工作50%的时间,你可以添加更多线程。
队列大小是 threadPool 在拒绝项目之前将接受的项目数。这是业务逻辑。这取决于你期望的行为:接受十亿个任务有意义吗?你什么时候扔毛巾?如果一个任务需要一秒钟才能完成,并且您有 10 个线程,则意味着队列中的第 10,000 个任务有望在 1000 秒内完成。这是可以接受的吗?最糟糕的事情是让客户端超时并重新提交相同的任务,然后你才能完成第一个任务。
原始 ELI12 答案:
这可能不是最准确的答案,但我会尝试:
一个简单的方法是要知道,您的 2 核 CPU 只能同时在两个线程上工作。
如果你有相对现代的英特尔CPU,并且你有超线程(又名。HT(TM)、HTT(TM)、SMT)已打开(通过 BIOS 中的设置),操作系统将看到可用内核的数量是 CPU 中物理内核数量的两倍。
无论哪种方式,从Java来检测您可以使用多少个内核(或同时不抢占彼此线程),只需调用int cores = Runtime.getRuntime().availableProcessors();
如果您尝试将您的申请视为研讨会(实际研讨会):
- 处理者将由员工表示。它是为产品增加价值的物理单位。
- 任务将是一团原材料(加上一些说明列表)
- 你的线程是一张桌子,员工可以在上面放置任务并在上面工作。
- 队列大小是将原材料带到办公桌上的传送带的长度。
因此,您的问题变成了“在员工数量不变的情况下,我如何选择在工厂内放置多少张桌子以及传送带可以放置多长时间?
对于多少张桌子(线程)部分:
一名员工一次只能在一张办公桌上工作,并且每张办公桌只能有一名员工。因此,基本设置是至少拥有与员工一样多的办公桌(以避免任何员工(处理者)被遗漏而没有任何工作的可能性。
但是,根据您的活动,您可能会为每位员工提供更多的办公桌:
如果你的员工需要不断地把邮件放在信封里,那么一个需要他们全神贯注的操作(在编程中:对集合进行排序,创建对象,增加计数器),拥有更多的办公桌将无济于事,甚至可能是有害的,因为你的员工有时不得不更换办公桌(切换上下文,这需要一些时间),从而离开他们正在处理的办公桌, 在另一个方面取得工作进展。
但是,如果您的任务是制作陶器,并且依赖于您的员工等待粘土在烤箱中烹饪(了解访问外部资源,例如文件系统,Web服务等),那么您的员工可以负担得起在另一张桌子上建模粘土,然后再回到第一张桌子上。
因此,只要您的任务具有足够大的有效工作/等待比率(运行/等待),您就可以为每个员工负担更多的办公桌。办公桌的数量是员工在等待期间可以完成多少任务。
对于输送带(队列)尺寸部分:
队列大小表示在开始拒绝任何更多任务(通过引发异常)之前允许排队的项目数,因此是您开始告诉“好吧,我已经超额预订并且永远无法遵守”的阈值
首先,我想说的是,您的传送带需要安装在车间内。这意味着集合应该足够小,以防止内存不足错误(显然)。
之后,它基于您的公司政策。假设每次客户端下订单时都会向传送带添加一个任务(另一个服务调用您的 API)。如果呼叫者不关心您花多少时间来遵守并充分信任您执行,那么限制传送带的大小就没有意义。
但是,如果您可以期望您的客户在等待他们的陶器一个月后感到恼火,并让您同时或重新订购另一个陶器,假设第一个订单丢失并且不会费心检查第一个订单是否已完成......第一个订单是徒劳的,你不会得到报酬,如果你的客户在你太慢而无法遵守时下另一个订单,你就会进入一个反馈循环,因为每个新订单都会减慢整个过程。
因此,在这种情况下,您应该举出一个标志,告诉您的客户“对不起,我们超额预订了,您现在不应该下任何新订单,因为我们将无法在可接受的时间范围内遵守”。
然后,队列大小将为:可接受的时间范围/完成任务的时间。
具体示例:如果您的客户服务期望它提交的任务必须在不到100秒的时间内完成,并且知道每个任务需要1-2秒,则应将队列限制为50-100个任务,因为一旦您在队列中有100个任务等待,您就非常确定下一个任务不会在不到100秒的时间内完成, 从而拒绝任务以防止服务无处等待。