在Julia中使用while循环时,print("")的作用是什么?

4

我在julia中遇到了一个奇怪的bug。基本上,在合适的地方添加一个print("")语句会以一种积极的方式改变以下代码的行为。我感到非常困惑。为什么?

xs = [1,2,3,4,5,6,7,8]

cmds = [`sleep $x` for x in xs]

f = open("results.txt", "w")

i = 1
nb_cmds = length(cmds)
max_running_ps = 3
nb_running_ps = 0
ps = Dict()

while true
    # launching new processes if possible
    if nb_running_ps < max_running_ps
        if i <= nb_cmds && !(i in keys(ps))
            print("spawn:")
            println(i)
            p = spawn(cmds[i], Base.DevNull, f, f)
            setindex!(ps,p,i)
            nb_running_ps = nb_running_ps + 1
            i = i+1
        end
    end
    # detecting finished processes to be able to launch new ones
    for j in keys(ps)
        if process_exited(ps[j])
            print("endof:")
            println(j)
            delete!(ps,j)
            nb_running_ps = nb_running_ps - 1
        else
            print("")
            # why do I need that ????
        end
    end
    # nothing runs and there is nothing to run
    if nb_running_ps <= 0 && i > nb_cmds
        break
    end
end

close(f)

println("finished")

实际上,命令比sleep更有用。

如果删除或注释print(""),条件语句"if process_exited(ps[j])"的内容似乎永远不会运行,即使前max_running_ps个进程已经完成,程序仍会陷入无限循环。

一些背景:我需要运行一段代码,这段代码需要很长时间才能运行(并且使用大量内存),针对一组参数(在此处由x表示)的不同值进行运行。由于它们需要很长时间,我想要并行运行它们。另一方面,不同的运行之间几乎没有共享内容,因此通常的并行工具并不真正相关。最后,我想避免简单的pmap,首先是为了避免如果出现故障就失去所有内容,其次是因为在运行过程中获得部分结果可能是有用的。因此,我使用julia编写了这段代码(因为实际计算的主要代码是用julia编写的)。


print 是异步的(出于性能原因)并且会产生 yield。也许可以尝试使用 @sync print("") 代替?如果这样解决了你的问题,那么我会将其发布为答案。 - Fengyang Wang
实际上,我通过添加print("")(即使没有@sync)已经“解决”了我的问题。 然而,我不理解为什么会这样,因此有了我的问题。 - Georg Sievelson
那么你的问题正好相反:你需要异步行为(以便进行任务切换),而print提供了这种功能。我很快会发布一个答案。 - Fengyang Wang
1个回答

4

虽然这不是一个错误,但如果您不习惯此类异步编程,可能会感到惊讶。

默认情况下,Julia是单线程的,一次只能运行一个任务。为了完成任务,Julia需要切换到该任务。每当当前任务yield时,任务就会被切换。

print也是异步操作,因此它会为您产生yield,但更简单的方法是使用yield(),它可以实现相同的结果。有关异步编程的更多信息,请参见文档


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接