Julia 进度条使循环变慢

Julia 进度条使循环变慢,julia,Julia,我用进度条做了一些测试,它大大降低了测试代码的速度。 是否有其他选择或解决方案?我正在寻找一种在循环过程中跟踪当前索引的方法,有一些原始的方法可以在达到步骤时设置更多的打印条件,但是否有一些内置的好方法? 哦,还有一个问题,有没有办法打印函数启动后经过的时间并显示索引?让我澄清一下,我知道@time等,但有没有办法计算时间并用相应的索引显示它,如 “在时间$time中迭代达到索引$i” 已完成测试的代码: function test(x) summ = BigInt(0); Juno

我用进度条做了一些测试,它大大降低了测试代码的速度。 是否有其他选择或解决方案?我正在寻找一种在循环过程中跟踪当前索引的方法,有一些原始的方法可以在达到步骤时设置更多的打印条件,但是否有一些内置的好方法? 哦,还有一个问题,有没有办法打印函数启动后经过的时间并显示索引?让我澄清一下,我知道@time等,但有没有办法计算时间并用相应的索引显示它,如
“在时间$time中迭代达到索引$i”
已完成测试的代码:

function test(x)
   summ = BigInt(0);
   Juno.progress(name = "foo") do id
       for i = 1:x
           summ+=i;
           @info "foo" progress=i/x _id=id
       end
   end
   println("sum up to $x is $summ");
   return summ;
end
@benchmark test(10^4)

function test2(x)
   summ = BigInt(0);
   for i = 1:x
       summ+=i;
       (i%10 == 0) && println("Reached this milestone $i")
   end
   println("sum up to $x is $summ");
   return summ;
end
@benchmark test2(10^4)
编辑1

朱诺进展:

BenchmarkTools.Trial: 
memory estimate:  21.66 MiB
allocs estimate:  541269
--------------
minimum time:     336.595 ms (0.00% GC)
median time:      345.875 ms (0.00% GC)
mean time:        345.701 ms (0.64% GC)
maximum time:     356.436 ms (1.34% GC)
--------------
samples:          15
evals/sample:     1
对于粗略的简单版本:

BenchmarkTools.Trial: 
memory estimate:  1.22 MiB
allocs estimate:  60046
--------------
minimum time:     111.251 ms (0.00% GC)
median time:      117.110 ms (0.00% GC)
mean time:        119.886 ms (0.51% GC)
maximum time:     168.116 ms (15.31% GC)
--------------
samples:          42
evals/sample:     1
正如向屏幕上写入所述,从根本上说,速度很慢(人类的速度非常快,计算机的速度非常慢)。您可以放弃将输出写入进度条,但也可以简单地减少更新进度条的频率。在您的测试用例中,您要添加10000个内容,并更新进度条10000次。老实说,我从来没有用过Julia,我也不知道进度条是什么样子。即使它是4K屏幕上的一个GUI进度条,并且每一次更新实际上都会改变它,我保证人看不到区别。我会在开始时(为0)和结束时(为100%)对其进行更新,然后使用带模测试的if语句,仅每隔这么多个加法更新一次。下面的python示例是伪代码,因为我从未使用过julia:

updateEvery = 2
for i in range(1,x):
    sum += i
    if x % updateEvery == 0:
        updateProgressBar(i/x)
通过改变updateEvery,可以减少或增加进度条更新的数量。您甚至可以基于x动态计算它,比如updateEvery=x/100,这意味着进度条将非常符合百分比。对于较小的x值,进度条更新所导致的效率低下也可能毫无意义,并且随着x的增加,每个要添加的数字的更新数将减少(因为更新总数将保持不变)


哦,如果你真的需要很好的性能来达到计数时钟滴答的水平(你可能不需要)。我想Julia会为您解决这个优化问题,您可以使用%并将updateEvery的值四舍五入到下一个2次方。不过,如果您真的关心这个性能级别,您最好干脆去掉进度条,以完全消除循环。

我建议使用
Juno.@progress
直接用于r更好的性能:

using BenchmarkTools

function test(x)
    summ = BigInt(0)
    Juno.progress(name = "foo") do id
        for i = 1:x
            summ += i
            @info "foo" progress = i / x _id = id
        end
    end
    println("sum up to $x is $summ")
    return summ
end
@benchmark test(10^4) # min: 326ms

function test1(x)
    summ = BigInt(0)
    Juno.@progress "foo" for i = 1:x
        summ += i
    end
    println("sum up to $x is $summ")
    return summ
end
@benchmark test1(10^4) # min 5.4ms

function test2(x)
    summ = BigInt(0)
    for i = 1:x
        summ += i
    end
    println("sum up to $x is $summ")
    return summ
end
@benchmark test2(10^4) # min 0.756ms


function test3(x)
   summ = BigInt(0);
   for i = 1:x
       summ+=i;
       (i%10 == 0) && println("Reached this milestone $i")
   end
   println("sum up to $x is $summ");
   return summ;
end
@benchmark test3(10^4) # min 33ms
Juno.progress
无法为您进行任何性能优化,但您可以手动实施它们:

function test4(x)
    summ = BigInt(0)
    update_interval = x÷200 # update every 0.5%
    Juno.progress(name = "foo") do id
        for i = 1:x
            summ += i
            if i % update_interval == 0
                @info "foo" progress = i / x _id = id
            end
        end
    end
    println("sum up to $x is $summ")
    return summ
end
@benchmark test4(10^4) # min: 5.2ms

从根本上说,向屏幕写入数据是缓慢的。最好的解决方案是:(a)让自己确信代码运行正确(换句话说,测试代码),然后(b)相信它能尽快完成工作,而不必过分关注它的进度。还要注意朱诺的
@progress
宏(for
for
循环)它比您的版本更复杂,因为它不会在每次迭代时生成日志条目(相反,它只在循环进度超过0.5%时才会生成日志条目——这仍然有开销,但比您正在做的要小得多)。问题是,我希望这个工具能帮助我在运行时间长时进行调试,我正在解决Euler项目中的问题,如果算法不好,有时计算时间会很长。但这个实现可以让你知道计算所需的时间。有时,即使有一个好的算法,也可能需要一段时间,这也取决于机器但当处理未知时,它有助于查看它在10、50或80%之后是否会卡住。我将用@benchmark results编辑我的代码,这样你就会看到我所说的差异。在我的机器
test
上快速的非常粗糙的实现比纯循环和
Juno大约慢430倍。@progress
版本慢了约7倍。在Julia中,据我在文档中阅读,默认情况下每0.5%更新一次,因此在我的示例中,每
50次
迭代一次。我可以按照您的建议尝试降低阈值,但这似乎有点毫无意义,因为我的原始
println(“…”)
每10次迭代输出的效果更好。问题可能更多地指向@progress函数的内部工作。更不用说纯代码运行速度大约是
4ms
的100倍。这不会对我的方法产生任何影响,因为你调用progress的次数会减少,所以不管是什么@probem的进度会减慢,但不会经常发生。虽然对原始问题不重要(我想它的计算更复杂),对于这样一个简单的循环,您在执行
%
时会损失大量时间,这是一个相当长的计算过程。如果可能,最好避免在紧循环中使用它,例如在函数开头定义
cnt=0
,如果cnt==update_interval;cnt=0;#progress…;否则cnt+=1
(因此不允许我在注释模式下正确识别代码)。