我正在通过AWS的ECS上的Docker运行任务。该任务执行一些受CPU限制的计算,我想并行运行这些计算。我以Runtime.getRuntime().availableProcessors()
中指定的线程数启动线程池,该线程池在PC上本地运行良好。出于某种原因,在AWS ECS上,即使有多个可用核心,该值始终返回1。因此,我的计算是按顺序进行的,并且没有使用多核。
例如,现在,我有一个任务在“ t3.medium”实例上运行,根据docs,该实例应具有2个内核。
当我执行以下代码时:
System.out.println("Java reports " +
Runtime.getRuntime().availableProcessors() + " cores");
然后在日志上显示以下内容:
Java reports 1 cores
我没有在ECS的任务定义中指定cpu
参数。我在ECS管理控制台中的任务列表中看到它的“ CPU”列显示为0。我还注意到,在实例(= VM)列表中,它将“ CPU可用”列为2048,这大概与VM具有2个内核这一事实有关。
我希望我的Java程序能够看到VM必须提供的所有内核。 (通常,Java程序在没有Docker的计算机上运行时就是这种情况。)
我该怎么做?
答案 0 :(得分:0)
感谢@stdunbar在评论中指出我的正确方向。
编辑:感谢@Imran的评论。如果您启动大量线程,则绝对会将它们调度到多个内核。这个答案只是关于让Runtime.getRuntime().availableProcessors()
返回正确的值。许多“线程池”启动的线程数量与该方法返回的数量一样:它应该返回可用内核的数量。
似乎有两个主要解决方案,但这两个都不是理想的解决方案:
在任务定义中设置cpu
参数。例如,如果您有2个核心并且要同时使用它们,则必须在任务的定义中设置"cpu":2048
。这不是很方便,原因有两个:
如果选择更大的实例,则必须确保更新此参数。
如果您希望同时运行两个任务,而这两个任务都可以偶尔使用所有内核进行短期活动,则AWS不会在具有"cpu":2048
的2内核系统上安排两个任务。从CPU的角度来看,虚拟机已“满”。这违背了分担工作(Unix等)原则的每个任务都按需完成的工作(例如,想象一下在台式机上,如果您在双核计算机上运行Word和Excel,而Windows不允许您启动其他任何任务,因为Word 可能都需要一个核心,而Excel 可能也需要,所以如果另一个程序 可能需要全部同时没有足够的核心。)
按照here所述,在JDK 10及更高版本中使用-XX:ActiveProcessorCount=xx
JVM选项。这不方便,因为:
我写了更长的博客文章,描述了我的发现:https://www.databasesandlife.com/java-docker-aws-ecs-multicore/