【问题标题】:Total time taken and Average time taken by all the threads所有线程花费的总时间和平均花费的时间
【发布时间】:2013-03-16 20:52:56
【问题描述】:

我正在做一个项目,我需要测量程序花费的总时间和程序花费的平均时间。而且那个程序是一个多线程程序。

在该程序中,每个线程都在特定范围内工作。输入参数为Number of ThreadsNumber of Task

如果number of threads is 2number of tasks is 10 则每个线程都将执行10 tasks。所以这意味着 2 个线程将执行 20 tasks

也就是说——

第一个线程应该使用1 and 10之间的id,第二个线程应该使用11 and 20之间的id。

我得到了上述场景的工作。现在我想测量所有线程花费的总时间和平均时间是多少。所以我在我的程序中得到了以下设置。

问题陈述:-

谁能告诉我我试图通过所有线程测量Total time and Average time taken 的方式在我下面的程序中是否正确?

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

long startTime = 0L;
try {

    readPropertyFiles();

    startTime = System.nanoTime();

    // queue some tasks
    for (int i = 0, nextId = startRange; i < noOfThreads; i++, nextId += noOfTasks) {

        service.submit(new XMPTask(nextId, noOfTasks, tableList));
    }

    service.shutdown();
    service.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);

} finally {
    long estimatedTime = System.nanoTime() - startTime;
    logTimingInfo(estimatedTime, noOfTasks, noOfThreads);
}



private static void logTimingInfo(long elapsedTime, int noOfTasks, int noOfThreads) {

    long timeInMilliseconds = elapsedTime / 1000000L;
    float avg = (float) (timeInMilliseconds) / noOfTasks * noOfThreads;

    LOG.info(CNAME + "::" + "Total Time taken " + timeInMilliseconds + " ms. And Total Average Time taken " + avg + " ms");
}

【问题讨论】:

    标签: java multithreading average executorservice


    【解决方案1】:

    service.submit 仅被执行noOfThreads 次。 XMPTask 对象的创建次数相同。

    【讨论】:

      【解决方案2】:

      您测量的时间不是消耗时间,而是经过时间。

      如果测试的程序(JVM)是​​计算机上唯一的程序,它可能相对准确,但在现实世界中很多进程同时运行。

      我已经通过在 Windows(我将在星期一在我的办公室完成这篇文章)和 Linux (/proc) 上对操作系统进行本机调用来完成这项工作。

      【讨论】:

      • 仅供参考,上面的程序,我将在一台专门用于我的 LNP 测试的机器上运行。
      【解决方案3】:

      我认为您需要测量任务类本身 (XMPTask) 中的时间。在该任务中,您应该能够提取正在执行它的线程的 ID 并记录它。使用这种方法需要阅读日志并对它们进行一些计算。

      另一种方法是随着时间的推移保持运行总计和平均值。为此,您可以编写一个简单的类,将其传递给每个任务,该任务具有一些静态(每个 jvm)变量,用于跟踪每个线程正在做什么。然后你可以在 Threadpool 之外有一个单独的线程来进行计算。所以如果你想报告每个线程每秒的平均cpu时间,这个计算线程可以休眠一秒钟,然后计算并记录所有平均时间,然后休眠一秒钟......

      编辑:重新阅读需求后,您不需要后台线程,但不确定我们是在跟踪每个线程的平均时间还是每个任务的平均时间。我假设了每个线程的总时间和平均时间,并在下面的代码中充实了这个想法。它尚未经过测试或调试,但应该可以让您很好地了解如何开始:

      public class Runner
      {
          public void startRunning()
          {
              // Create your thread pool
              ExecutorService service = Executors.newFixedThreadPool(noOfThreads);
      
              readPropertyFiles();
      
              MeasureTime measure = new MeasureTime();
      
              // queue some tasks
              for (int i = 0, nextId = startRange; i < noOfThreads; i++, nextId += noOfTasks) 
              {
      
                  service.submit(new XMPTask(nextId, noOfTasks, tableList, measure));
              }
      
              service.shutdown();
              service.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
              measure.printTotalsAndAverages();
          }
      }
      
      public class MeasureTime
      {
          HashMap<Long, Long> threadIdToTotalCPUTimeNanos = new HashMap<Long, Long>();
          HashMap<Long, Long> threadIdToStartTimeMillis = new HashMap<Long, Long>();
          HashMap<Long, Long> threadIdToStartTimeNanos = new HashMap<Long, Long>();
      
          private void addThread(Long threadId)
          {
              threadIdToTotalCPUTimeNanos.put(threadId, 0L);
              threadIdToStartTimeMillis.put(threadId, 0L);
          }
      
          public void startTimeCount(Long threadId)
          {
              synchronized (threadIdToStartTimeNanos)
              {
                  if (!threadIdToStartTimeNanos.containsKey(threadId))
                  {
                      addThread(threadId);
                  }
      
                  long nanos = System.nanoTime();
                  threadIdToStartTimeNanos.put(threadId, nanos);
              }
          }
      
          public void endTimeCount(long threadId)
          {
              synchronized (threadIdToStartTimeNanos)
              {
                  long endNanos = System.nanoTime();
                  long startNanos = threadIdToStartTimeNanos.get(threadId);
      
                  long nanos = threadIdToTotalCPUTimeNanos.get(threadId);
                  nanos = nanos + (endNanos - startNanos);
                  threadIdToTotalCPUTimeNanos.put(threadId, nanos);
              }
          }
      
          public void printTotalsAndAverages()
          {
              long totalForAllThreadsNanos = 0L;
              int numThreads = 0;
              long totalWallTimeMillis = 0;
              synchronized (threadIdToStartTimeNanos)
              {
                  numThreads = threadIdToStartTimeMillis.size();
                  for (Long threadId: threadIdToStartTimeNanos.keySet())
                  {
                      totalWallTimeMillis += System.currentTimeMillis() - threadIdToStartTimeMillis.get(threadId);
                      long totalCPUTimeNanos = threadIdToTotalCPUTimeNanos.get(threadId);
      
                      totalForAllThreadsNanos += totalCPUTimeNanos;
                  }
              }
      
              long totalCPUMillis = (totalForAllThreadsNanos)/1000000;
              System.out.println("Total milli-seconds for all threads: " + totalCPUMillis);
              double averageMillis = totalCPUMillis/numThreads;
              System.out.println("Average milli-seconds for all threads: " + averageMillis);
      
              double averageCPUUtilisation = totalCPUMillis/totalWallTimeMillis;
              System.out.println("Average CPU utilisation for all threads: " + averageCPUUtilisation);
          }
      }
      
      public class XMPTask implements Callable<String>
      {
          private final MeasureTime measure; 
      
          public XMPTask(// your parameters first
                  MeasureTime measure)
          {
              // Save your things first
      
              this.measure = measure;
          }
      
          @Override
          public String call() throws Exception
          {
              measure.startTimeCount(Thread.currentThread().getId());
      
              try
              {
                  // do whatever work here that burns some CPU.
              }
              finally
              {
                  measure.endTimeCount(Thread.currentThread().getId());
              }
      
              return "Your return thing";
          }
      }
      

      在写完这一切之后,有一件事情似乎有点奇怪,因为 XMPTask 似乎对任务列表了解太多,我认为你应该为你拥有的每个任务创建一个 XMPTask,给它有足够的信息来完成这项工作,并在您创建它们时将它们提交给服务。

      【讨论】:

      • 感谢 hack_on 的建议。你的第二种方法是个好主意。你能为我的第二种方法提供一个简单的例子吗?感谢您的帮助。
      猜你喜欢
      • 1970-01-01
      • 2014-02-20
      • 1970-01-01
      • 1970-01-01
      • 2020-06-30
      • 1970-01-01
      • 2021-04-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多