【问题标题】:Executing some code only once in a Thread region在线程区域中只执行一次代码
【发布时间】:2017-09-27 16:27:04
【问题描述】:

在我正在工作的 Java 代码的某个部分,我需要在 run() 方法中放置一个计时器。每个线程将执行run() 内的所有代码。但我需要在块 (1) 之后和代码块 (2) 之前开始测量,因此需要在那里触发计时器。

for (int i = 0; i < total_threads-1; i++){
   final int id = i+1;          
   th[i] = new Thread(new Runnable() {              
       public final void run(){
             /* ... block of code (1) executed by multiple threads ... */

             /* How can i start this counter only once? */
             final long begin = System.currentTimeMillis();

             /* ... another block of code (2) executed by multiple threads i need to measure!!! ... */
       }
    });
    th[i].start();
}

for(int i = 0 ; i < total_threads-1 ; i++) {
    try {
           th[i].join();
        }
    catch (InterruptedException e) {}
}

final long end = System.currentTimeMillis();

System.out.println((end-begin) / 1000.0);

但是所有线程都有自己的begin 变量并启动计数器,这是一个问题,因为System.currentTimeMillis() 应该被触发一次,而不是由许多线程触发。 我可能可以将run() 的代码分隔在两个不同的并行区域中,但这意味着两次创建线程是不可接受的(就性能而言)。 使用 Java 线程的 Java 是否有类似的 OpenMP 指令 #pragma omp master 技术? 我怎样才能在这里正确测量时间?

【问题讨论】:

  • 为每个具有相同值 System.currentTimeMillis 的线程设置单独的 begin 变量有什么意义(如您所愿,它应该只触发一次!)??

标签: java performance openmp hpc performance-measuring


【解决方案1】:

最简单的方法就是在主线程(即创建所有子线程的线程)中而不是在子线程中记录时间。

但如果你真的想在孩子中启动计时器(也许有一些昂贵的设置?),你可以使用 Guava StopWatch 对象。

代码如下所示:

StopWatch timer = StopWatch.createUnstarted();
for (int i = 0; i < total_threads-1; i++){
    final int id = i+1;
    th[i] = new Thread(() -> {
        /* ... block of code (1) executed by multiple threads ... */

        try {
            synchronized (timer) {
                timer.start();
            }
        } catch (IllegalStateException e) {
            // ignore; the watch is already started
        }

        /* ... another block of code (2) executed by multiple threads i need to measure!!! ... */
    });
    th[i].start();
}

for(int i = 0 ; i < total_threads-1 ; i++) {
    try {
        th[i].join();
    } catch (InterruptedException e) {}
}

timer.stop();

System.out.println(timer.elapsed(TimeUnit.SECONDS));

【讨论】:

  • 感谢您的帮助,但很遗憾没有奏效。您的解决方案导致执行错误:“线程“主”java.lang.IllegalStateException 中的异常:此秒表已停止。”该问题是由 run() 方法内部的测量引起的。如果我输入:try { synchronized(timerThreads){ timerThreads.start(); } } catch (IllegalStateException e) {} 外部run() 程序运行良好,但没有执行应有的操作。
  • 为什么要在子线程中启动定时器?为什么不像我建议的那样只在主线程中进行所有计时?您收到的错误表明您的线程从未启动过计时器。你是不是等到join之后才到stop呢?你有任何子线程吗?
  • 我实际上解决了测量大师时间的问题。没有意识到实际上主人会等待所有线程完成他们的工作,所以测量主人的工作就可以完成这项工作。感谢您的帮助
  • @CarlosSá 随意将此答案标记为正确。我建议测量主线程中的所有内容。
【解决方案2】:

您可以检查线程 ID 以执行一次 prefer 行:

if (id == YOUR_THREAD_ID) 
{
     begin = System.currentTimeMillis();
}

【讨论】:

  • 这可能行不通,因为begin 必须是最终的,所以不能被子线程修改。
猜你喜欢
  • 2021-11-25
  • 2014-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-20
  • 1970-01-01
相关资源
最近更新 更多