当前位置: 首页 > 面试题库 >

newFixedThreadPool与newSingleThreadExecutor的性能问题

洪国兴
2023-03-14
问题内容

我正在尝试对我们的客户代码进行基准测试。因此,我决定编写一个多线程程序来对我的客户端代码进行基准测试。我正在尝试测量time (95 Percentile)下面的方法需要多少?

attributes = deClient.getDEAttributes(columnsList);

因此,下面是我编写的用于对上述方法进行基准测试的多线程代码。在两种情况下,我看到了很多变化-

1)首先,使用20 threads和来处理多线程代码running for 15 minutes。我得到95%的37ms。我正在使用-

ExecutorService service = Executors.newFixedThreadPool(20);

2)但是,如果我运行相同的程序以15 minutes使用-

ExecutorService service = Executors.newSingleThreadExecutor();

代替

ExecutorService service = Executors.newFixedThreadPool(20);

7ms当我使用运行代码时,我得到95%,比上面的数字要少得多newFixedThreadPool(20)

谁能告诉我以下原因导致此类高性能问题的原因是什么?

newSingleThreadExecutor vs newFixedThreadPool(20)

而且通过两种方式我都运行我的程序15 minutes

以下是我的代码-

public static void main(String[] args) {

    try {

        // create thread pool with given size
        //ExecutorService service = Executors.newFixedThreadPool(20);
        ExecutorService service = Executors.newSingleThreadExecutor();

        long startTime = System.currentTimeMillis();
        long endTime = startTime + (15 * 60 * 1000);//Running for 15 minutes

        for (int i = 0; i < threads; i++) {
            service.submit(new ServiceTask(endTime, serviceList));
        }

        // wait for termination        
        service.shutdown();
        service.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
    } catch (InterruptedException e) {

    } catch (Exception e) {

    }
}

下面是实现Runnable接口的类-

class ServiceTask implements Runnable {

    private static final Logger LOG = Logger.getLogger(ServiceTask.class.getName());
    private static Random random = new SecureRandom();

    public static volatile AtomicInteger countSize = new AtomicInteger();

    private final long endTime;
    private final LinkedHashMap<String, ServiceInfo> tableLists;

    public static ConcurrentHashMap<Long, Long> selectHistogram = new ConcurrentHashMap<Long, Long>();


    public ServiceTask(long endTime, LinkedHashMap<String, ServiceInfo> tableList) {
        this.endTime = endTime;
        this.tableLists = tableList;
    }

    @Override
    public void run() {

        try {

            while (System.currentTimeMillis() <= endTime) {

                double randomNumber = random.nextDouble() * 100.0;

                ServiceInfo service = selectRandomService(randomNumber);

                final String id = generateRandomId(random);
                final List<String> columnsList = getColumns(service.getColumns());

                List<DEAttribute<?>> attributes = null;

                DEKey bk = new DEKey(service.getKeys(), id);
                List<DEKey> list = new ArrayList<DEKey>();
                list.add(bk);

                Client deClient = new Client(list);

                final long start = System.nanoTime();

                attributes = deClient.getDEAttributes(columnsList);

                final long end = System.nanoTime() - start;
                final long key = end / 1000000L;
                boolean done = false;
                while(!done) {
                    Long oldValue = selectHistogram.putIfAbsent(key, 1L);
                    if(oldValue != null) {
                        done = selectHistogram.replace(key, oldValue, oldValue + 1);
                    } else {
                        done = true;
                    }
                }
                countSize.getAndAdd(attributes.size());

                handleDEAttribute(attributes);

                if (BEServiceLnP.sleepTime > 0L) {
                    Thread.sleep(BEServiceLnP.sleepTime);
                }
            }
        } catch (Exception e) {

        }
    }
}

更新:-

这是我的处理器规格-我正在Linux机器上运行程序,其中2个处理器定义为:

vendor_id       : GenuineIntel
cpu family      : 6
model           : 45
model name      : Intel(R) Xeon(R) CPU E5-2670 0 @ 2.60GHz
stepping        : 7
cpu MHz         : 2599.999
cache size      : 20480 KB
fpu             : yes
fpu_exception   : yes
cpuid level     : 13
wp              : yes
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss syscall nx rdtscp lm constant_tsc arch_perfmon pebs bts rep_good xtopology tsc_reliable nonstop_tsc aperfmperf pni pclmulqdq ssse3 cx16 sse4_1 sse4_2 popcnt aes hypervisor lahf_lm arat pln pts
bogomips        : 5199.99
clflush size    : 64
cache_alignment : 64
address sizes   : 40 bits physical, 48 bits virtual
power management:

问题答案:

谁能告诉我newSingleThreadExecutorvs 如此高性能问题的原因是什么newFixedThreadPool(20)

如果并行运行的任务(如果是20个)比处理器(我怀疑您有20个以上的处理器)要多得多,那么是的,每个单独的任务将需要更长的时间才能完成。对于计算机而言,一次执行一个任务比在同时运行的多个线程之间切换要容易得多。即使将池中的线程数限制为拥有的CPU数,每个任务的运行速度可能也会变慢,尽管会略有降低。

但是,如果比较不同大小的线程池的 吞吐量
(完成多个任务所需的时间),则应该看到20个线程的吞吐量应该更高。如果您用20个线程执行1000个任务,则总体而言,完成任务要比仅使用1个线程快得多。每个任务可能需要更长的时间,但它们将并行执行。给定线程开销等,它可能不会快20倍,但是可能快15倍。

您不必担心单个任务的速度,而应该通过调整池中的线程数来尝试最大化任务吞吐量。使用多少线程在很大程度上取决于IO数量,每个任务使用的CPU周期,锁,同步块,在OS上运行的其他应用程序以及其他因素。

就池中的线程数而言,人们通常会使用1-2倍的CPU作为启动内存的最佳位置,以最大程度地提高吞吐量。更多的IO请求或线程阻塞操作将添加更多的线程。更多的CPU绑定将减少线程数,使其更接近可用的CPU数。如果您的应用程序正在与服务器上其他更重要的应用程序竞争OS周期,则可能需要更少的线程。



 类似资料:
  • 可以通过调用Executors类的静态newFixedThreadPool()方法获得固定的线程池。 语法 (Syntax) ExecutorService fixedPool = Executors.newFixedThreadPool(2); 哪里 最多2个线程将处于活动状态以处理任务。 如果提交的线程超过2个,则它们将保留在队列中,直到线程可用。 如果线程在执行器执行关闭期间因故障而终止,

  • 可以通过调用Executors类的静态newSingleThreadExecutor()方法来获取单个线程池。 语法 (Syntax) ExecutorService executor = Executors.newSingleThreadExecutor(); 其中newSingleThreadExecutor方法创建一次执行单个任务的执行程序。 例子 (Example) 以下TestThre

  • 我试着使用ActiveMQ组件(在Spring Boot内部),但最终得到了一些奇怪的结果。 1-我从SEDA发送了2000条消息到目的地队列 我是这样做的: 2-现在我尝试使用中的这些文件,我将这样做: 所以我的问题是: 1-为什么我将文件发送到队列时速度非常慢?但我可以如此快速地使用这些消息(在这个测试中,它比以前快了50倍多)!!! 我在笔记本电脑上消费和生产了这两种东西。 任何帮助都将不胜

  • 问题内容: 我读到React非常快。最近,我写了一个应用程序来测试对角的反应。不幸的是,我发现反应的表现要慢于角度反应。 http://shojib.github.io/ngJS/#/speedtest/react/1 这是react的源代码。我是新来的人。我确定我的反应代码在这里做错了。我发现它异常缓慢。 https://jsbin.com/viviva/edit?js,输出 看看是否有任何反应

  • 问题内容: 最近,我在查询性能方面遇到了一些问题。经过长时间的努力,我终于发现带有select前缀的查询如下: 是慢300倍,然后以这种方式启动查询: 有人可以帮我吗,为什么呢?关于此的一些外部文档将非常有用。 用于测试的表是: SALES_UNIT 表包含一些基本的信息 自动售货机 节点,例如名称等。唯一的关联是表SALES_UNIT_TYPE,例如ManyToOne。主键是ID和字段VALID

  • 问题内容: 我们有一个本机应用程序,它使用GPU(OpenCL)通过一种特定的方法处理大数据,并且运行得很好,没有问题。该项目的一部分(网络和分发)由进行开发,我们只需要调用本机应用程序/库即可。 我们试图使用类将其称为独立的外部过程。问题是我们无法控制应用程序(事件,处理程序,线程等)。我们还尝试将C代码转换为Java代码,但是性能下降了。除了将本机代码作为进程运行之外,我还在考虑JNA和JNI