Service times directly proportional to number of threads

前端 未结 2 1671
挽巷
挽巷 2020-12-12 05:04

My system is i5-Dual core with hyper-threading. Windows show me 4 processors. When i run a single optimized cpu-bound task by a single thread at a time its service time alw

2条回答
  •  心在旅途
    2020-12-12 05:36

    I timed this in a variety of scenarios, and with a slightly modified task, got times of ~45 ms with one thread and ~60 ms for two threads. So, even in this example, in one second, one thread can complete about 22 tasks, but two threads can complete 33 tasks.

    However, if you run a task that doesn't tax the garbage collector so grievously, you should see the performance increase you expect: two threads complete twice as many tasks. Here is my version of your test program.

    Note that I made one significant change to your task (DirtyTask): n was always 0, because you cast the result of Math.random() to an int (which is zero), and then multiplied by 13.

    Then I added a CleanTask that doesn't generate any new objects for the garbage collector to handle. Please test and report the results on your machine. On mine, I got this:

    Testing "clean" task.
    Average task time: one thread = 46 ms; two threads = 45 ms
    Testing "dirty" task.
    Average task time: one thread = 41 ms; two threads = 62 ms
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;
    import java.util.concurrent.ThreadLocalRandom;
    import java.util.concurrent.TimeUnit;
    import java.util.function.Supplier;
    
    final class Parallels
    {
    
      private static final int RUNS = 10;
    
      public static void main(String... argv)
        throws Exception
      {
        System.out.println("Testing \"clean\" task.");
        flavor(CleanTask::new);
        System.out.println("Testing \"dirty\" task.");
        flavor(DirtyTask::new);
      }
    
      private static void flavor(Supplier> tasks)
        throws InterruptedException, ExecutionException
      {
        ExecutorService warmup = Executors.newFixedThreadPool(100);
        for (int i = 0; i < 100; ++i)
          warmup.submit(tasks.get());
        warmup.shutdown();
        warmup.awaitTermination(1, TimeUnit.DAYS);
        ExecutorService workers = Executors.newFixedThreadPool(2);
        long t1 = test(1, tasks, workers);
        long t2 = test(2, tasks, workers);
        System.out.printf("Average task time: one thread = %d ms; two threads = %d ms%n", t1 / (1 * RUNS), t2 / (2 * RUNS));
        workers.shutdown();
      }
    
      private static long test(int n, Supplier> tasks, ExecutorService workers)
        throws InterruptedException, ExecutionException
      {
        long sum = 0;
        for (int i = 0; i < RUNS; ++i) {
          List> batch = new ArrayList<>(n);
          for (int t = 0; t < n; ++t)
            batch.add(tasks.get());
          List> times = workers.invokeAll(batch);
          for (Future f : times)
            sum += f.get();
        }
        return TimeUnit.NANOSECONDS.toMillis(sum);
      }
    
      /**
       * Do something on the CPU without creating any garbage, and return the 
       * elapsed time.
       */
      private static class CleanTask
        implements Callable
      {
        @Override
        public Long call()
        {
          long time = System.nanoTime();
          long x = 0;
          for (int i = 0; i < 15_000_000; i++)
            x ^= ThreadLocalRandom.current().nextLong();
          if (x == 0)
            throw new IllegalStateException();
          return System.nanoTime() - time;
        }
      }
    
      /**
       * Do something on the CPU that creates a lot of garbage, and return the 
       * elapsed time.
       */
      private static class DirtyTask
        implements Callable
      {
        @Override
        public Long call()
        {
          long time = System.nanoTime();
          String s = "";
          for (int i = 0; i < 10_000; i++)
            s += (int) (ThreadLocalRandom.current().nextDouble() * 13);
          if (s.length() == 10_000)
            throw new IllegalStateException();
          return System.nanoTime() - time;
        }
      }
    
    }
    

提交回复
热议问题