0

What is the best way to check which index is executing in a loop without too much slow down the process?

For example I want to find all long fancy numbers and have a loop like

for( long i = 1; i > 0; i++){
    //block
}

and I want to learn which i is executing in real time.

Several ways I know to do in the block are printing i every time, or checking if(i % 10000), or adding a listener.

Which one of these ways is the fastest. Or what do you do in similar cases? Is there any way to access the value of the i manually?

4

4 回答 4

1

我最近的大部分经验都是使用 Java,所以我会写这样的东西

import java.util.concurrent.atomic.AtomicLong;

public class Example {

    public static void main(String[] args) {
        AtomicLong atomicLong = new AtomicLong(1); // initialize to 1
        LoopMonitor lm = new LoopMonitor(atomicLong);
        Thread t = new Thread(lm);
        t.start(); // start LoopMonitor

        while(atomicLong.get() > 0) {
            long l = atomicLong.getAndIncrement(); // equivalent to long l = atomicLong++ if atomicLong were a primitive
            //block
        }
    }

    private static class LoopMonitor implements Runnable {
        private final AtomicLong atomicLong;

        public LoopMonitor(AtomicLong atomicLong) {
            this.atomicLong = atomicLong;
        }

        public void run() {
            while(true) {
                try {
                System.out.println(atomicLong.longValue()); // Print l
                Thread.sleep(1000); // Sleep for one second
                } catch (InterruptedException ex) {}
            }
        }
    }
}

即使在 32 位平台上,大多数 AtomicLong 实现也可以在一个时钟周期内设置,这就是为什么我在这里使用它而不是原始 long(你不想无意中打印半集 long);查看您的编译器/平台详细信息,看看您是否需要这样的东西,但如果您在 64 位平台上,那么无论您使用哪种语言,您都可以使用原始 long。修改后的 for 循环不会对效率造成太大影响 - 您已将原始 long 替换为对 long 的引用,因此您添加的只是指针取消引用。

于 2013-04-21T02:46:06.640 回答
1

这并不容易,但可能在不影响进程的情况下探测该值的唯一方法是使用另一个线程访问共享内存中的循环变量。线程库因系统而异,因此我无能为力(在 Linux 上我可能会使用 pthreads)。“监控”线程可能会做一些事情,比如每分钟探测一次值,在两者之间进行 sleep(),因此允许第一个线程不间断地运行。

于 2013-04-21T00:06:37.730 回答
1

要获得空成本报告(在多 CPU 计算机上):将您的索引设置为“全局”属性(例如全类),并有一个单独的线程来读取和报告索引值。
该报告可以是基于计时器的(每秒 5 次左右)。

Rq:也许你还需要一个布尔值来说明“我们在循环中吗?”。

于 2013-04-21T02:58:36.040 回答
1

易失性和缓存

如果您打算在 C/C++ 中执行此操作,并按照之前的建议使用单独的监视器线程,那么您必须使全局/静态循环变量 volatile。您不希望编译器决定为循环变量使用寄存器。无论如何,一些工具链都会做出这样的假设,但明确说明它并没有什么坏处。

然后是缓存的小问题。如今,一个单独的监视器线程最终将在一个单独的核心上结束,这意味着两个单独的缓存子系统必须就值是什么达成一致。这将不可避免地对循环的运行时间产生很小的影响。

实时约束?

所以这就引出了一个问题,即你的循环到底有多实时?我怀疑您的时序约束是否依赖于它在特定数量的 CPU 时钟周期内运行。两个原因,a) 没有现代操作系统可以保证你必须在裸机上运行,​​b) 现在大多数 CPU 在你背后改变自己的时钟频率,所以你不能指望对应于特定实时间隔的特定时钟周期数。

功能丰富的解决方案

因此,假设您的实时要求不受限制,您可能希望做一个功能更强大的监控线程。拥有一个受信号量保护的共享结构,您的循环偶尔会更新该信号量,并且您的监控线程会定期检查并报告进度。为了获得最佳性能,监视器线程将获取信号量,复制结构,释放信号量,然后检查/打印结构,最大限度地减少信号量锁定时间。

与先前答案中建议的方法相比,这种方法的唯一优点是您可以报告的不仅仅是循环变量的值。您可能还想报告来自循环块的更多信息。

如今,Linux 上的 C 语言中的互斥信号量非常快。除非您的循环块非常轻量级,否则单个互斥锁的运行时开销可能不会很大,尤其是当您每 1000 次循环迭代更新共享结构时。一个体面的操作系统会将你的线程放在不同的核心上,但为了更好的形式,你会让监控线程的优先级高于运行循环的线程。如果两个线程确实最终在同一个核心上,这将确保监视确实发生。

于 2013-04-21T06:05:14.827 回答