Practice - how many threads to create

How many threads are appropriate to create?

According to the article Java thread (middle): how many threads is it appropriate to create?

I summed up

  • Why use multithreading?

    Because when the program performs multiple tasks, it can execute faster, and the speed depends on the delay and throughput . Lower Latency, Increase Throughput

  • What are the application scenarios of multithreading?
    IO-intensive: operations such as dealing with disks and memory
    CPU-intensive: complex calculations, almost no disk operations, just constant calculations

  • How are threads created?

    The number of cpu-intensive threads is equal to the number of cpu cores (but in engineering, the number of threads is generally set to "CPU core number + 1" ), why?

    1. Assume that there is only cpu computing and a scenario with few or no io operations;

      • If the number of threads is less than the number of CPU cores, and if the amount of calculation is sufficient, each thread works normally without thread switching, but there are cases where the CPU cores are not utilized, which is insufficient CPU utilization.
      • If the number of threads is more than the number of CPU cores, if the amount of calculation is sufficient, then the extra threads will compete for CPU resources, resulting in the cost of thread switching.

​ The optimal number of io-intensive threads = number of CPU cores * [ 1 + (I/O time consumption / CPU time consumption)] (in engineering, generally the number of CPU cores * 2 + 1
20220706173915

Appropriate number of threads for io-intensive and cpu-intensive practices

local configuration

20220706174229

experimental code

/**
 * @author ggBall
 * @version 1.0.0
 * @ClassName IoTest.java
 * @Description TODO
 * @createTime 2022年07月06日 14:48:00
 */
public class PerformanceTest {
    
    

    String classFilePath = PerformanceTest.class.getResource("").getPath();

    CountDownLatch latch;

    /**
     * 按照公式 io密集型 线程数=核数*2+1 本机8核 线程数应该是17
     * 结果 20次的10000次io操作 (8核*2+1)10个线程操作 平均1705.3ms
     * 结果 20次的10000次io操作 (8核*2+1)11个线程操作 平均1605.35ms
     * 结果 20次的10000次io操作 (8核*2+1)12个线程操作 平均1595.45ms
     * 结果 20次的10000次io操作 (8核*2+1)13个线程操作 平均1625.1ms
     * 结果 20次的10000次io操作 (8核*2+1)14个线程操作 平均1648.65ms
     * 结果 20次的10000次io操作 (8核*2+1)15个线程操作 平均1654.95ms
     * 结果 20次的10000次io操作 (8核*2+1)16个线程操作 平均1655.3ms
     * 结果 20次的10000次io操作 (8核*2+1)17个线程操作 平均1645.5ms
     * 结果 20次的10000次io操作 (8核*2+1)18个线程操作 平均1645.6ms
     * 结果 20次的10000次io操作 (8核*2+1)19个线程操作 平均1661.35ms
     * 结果 20次的10000次io操作 (8核*2+1)20个线程操作 平均1675.95ms
     * @throws InterruptedException
     */
    @Test
    public void ioTest() throws InterruptedException {
    
    

        int ioTimes = 10000;
        int threadNum;
        for (int i1 = 10; i1 <= 20; i1++) {
    
    
            threadNum = i1;
            ArrayList<Long> times = new ArrayList<>();
            for (int i = 0; i < 20; i++) {
    
    
                long time = singleIo(ioTimes, threadNum);
                times.add(time);
            }
            Double avgTime = times.stream().collect(Collectors.averagingLong(item -> item));
//            System.out.println(times);
            System.out.println("结果 20次的"+ioTimes+"次io操作 (8核*2+1)"+threadNum+"个线程操作 平均"+avgTime+"ms");
        }



    }

    /**
     * 按照公式 cpu密集型 线程数=核数 本机8核 线程数应该是8
     * 结果 20次的10000次cpu操作 (8核*2+1)15个线程操作 平均2.0ms
     * 结果 20次的10000次cpu操作 (8核*2+1)14个线程操作 平均1.85ms
     * 结果 20次的10000次cpu操作 (8核*2+1)13个线程操作 平均2.0ms
     * 结果 20次的10000次cpu操作 (8核*2+1)12个线程操作 平均1.6ms
     * 结果 20次的10000次cpu操作 (8核*2+1)11个线程操作 平均1.5ms
     * 结果 20次的10000次cpu操作 (8核*2+1)10个线程操作 平均1.6ms
     * 结果 20次的10000次cpu操作 (8核*2+1)9个线程操作 平均1.55ms
     * 结果 20次的10000次cpu操作 (8核*2+1)8个线程操作 平均1.35ms
     * 结果 20次的10000次cpu操作 (8核*2+1)7个线程操作 平均1.4ms
     * 结果 20次的10000次cpu操作 (8核*2+1)6个线程操作 平均1.6ms
     * 结果 20次的10000次cpu操作 (8核*2+1)5个线程操作 平均1.45ms
     * 结果 20次的10000次cpu操作 (8核*2+1)4个线程操作 平均1.4ms
     * 结果 20次的10000次cpu操作 (8核*2+1)3个线程操作 平均1.0ms
     * 结果 20次的10000次cpu操作 (8核*2+1)2个线程操作 平均1.7ms
     * @throws InterruptedException
     */
    @Test
    public void cpuTest() throws InterruptedException {
    
    
        int cpuTimes = 10000;
        int threadNum;
        for (int i1 = 16; i1 > 1; i1--) {
    
    
            threadNum = i1;
            ArrayList<Long> times = new ArrayList<>();
            for (int i = 0; i < 20; i++) {
    
    
                long time = singleCPU(cpuTimes, threadNum);
                times.add(time);
            }
            Double avgTime = times.stream().collect(Collectors.averagingLong(item -> item));
//            System.out.println(times);
            System.out.println("结果 20次的"+cpuTimes+"次cpu操作 (8核*2+1)"+threadNum+"个线程操作 平均"+avgTime+"ms");
        }

    }

    /**
     * 执行单次多线程cpu任务
     * @param cpuTimes
     * @param threadNum
     * @return
     * @throws InterruptedException
     */
    private long singleCPU(int cpuTimes, int threadNum) throws InterruptedException {
    
    

        latch = new CountDownLatch(cpuTimes);

        long start = System.currentTimeMillis();
        // 170次io操作 (8核*2+1)17个线程操作
        ExecutorService executorService = Executors.newFixedThreadPool(threadNum);

        for (int i = 0; i < cpuTimes; i++) {
    
    
            CPUTasker tasker = new CPUTasker();
            executorService.submit(tasker);
        }

        latch.await();

        long end = System.currentTimeMillis();

//        System.out.println(end-start+"ms");
        return end-start;
    }


    /**
     * 执行单次多线程io任务
     * @param ioTimes
     * @param threadNum
     * @return
     * @throws InterruptedException
     */
    public long singleIo(int ioTimes,int threadNum) throws InterruptedException {
    
    
        latch = new CountDownLatch(ioTimes);

        long start = System.currentTimeMillis();
        // 170次io操作 (8核*2+1)17个线程操作
        ExecutorService executorService = Executors.newFixedThreadPool(threadNum);

        for (int i = 0; i < ioTimes; i++) {
    
    
            IoTasker tasker = new IoTasker();
            executorService.submit(tasker);
        }

        latch.await();

        long end = System.currentTimeMillis();

//        System.out.println(end-start+"ms");
        return end-start;
    }

    /**
     * io任务
     */
    class IoTasker implements Runnable{
    
    

        @Override
        public void run() {
    
    
            String fileName = "text.txt";
            FIleUtils fIleUtils = new FIleUtils();
            fIleUtils.writeFile(classFilePath+ "/" + fileName,"sda实打实大sss11212");
            try {
    
    
                fIleUtils.fileRead(classFilePath+ "/" + fileName);
//                System.out.println(Thread.currentThread().getName()+"io完成");
                latch.countDown();

            } catch (NoSuchFieldException e) {
    
    
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * cpu任务
     */
    class CPUTasker implements Runnable{
    
    

        @Override
        public void run() {
    
    
            for (int i = 0; i < 1024; i++) {
    
    
                for (int j = 0; j < 1024; j++) {
    
    
                    for (int k = 0; k < 1024; k++) {
    
    
                        
                    }
                }
            }
            latch.countDown();
        }
    }


}


Practice summary

From the experimental code, the number of threads set for io-intensive type does conform to 线程数=核数*2+1the formula, and the test results show that 17 threads take the least time; but the time-consuming of cpu-intensive type from 3 to 12 threads is about 1.5ms, which is quite 线程数=核数different from the formula ,
so the formula for setting threads is only a reference standard, and the production environment has to be tested in practice .

question

Practice summary

From the experimental code, the number of threads set for io-intensive type does conform to 线程数=核数*2+1the formula, and the test results show that 17 threads take the least time; but the time-consuming of cpu-intensive type from 3 to 12 threads is about 1.5ms, which is quite 线程数=核数different from the formula ,
so the formula for setting threads is only a reference standard, and the production environment has to be tested in practice .

question

I/O time consumption and CPU time consumption Don't know what tool to use for testing?

Guess you like

Origin blog.csdn.net/ZHUXIUQINGIT/article/details/125645568