Concurrency Julia language-@async tasks::Current目录中的状态

Concurrency Julia language-@async tasks::Current目录中的状态,concurrency,julia,working-directory,Concurrency,Julia,Working Directory,我注意到(阅读:捕获了一个生产bug)Julia中的不同任务-没有自己的工作目录,但是当前目录-是共享的。我意识到在操作系统级别,这是显而易见的(一个进程有一个工作目录) 我的问题是首先-是否有任何其他明显或不太明显的全局状态我应该注意(显然是环境变量,或任何全局变量) 第二,如果更多地记录这一点,或者通过任务抽象避免这一点,抽象中的“任务”,它(理论上)可以有自己的语义,就像移回工作目录一样 通过从代码中删除任何“cd()”调用,我们已经解决了产品缺陷,关键是-带有闭包抽象的cd()让我们产生

我注意到(阅读:捕获了一个生产bug)Julia中的不同任务-没有自己的工作目录,但是当前目录-是共享的。我意识到在操作系统级别,这是显而易见的(一个进程有一个工作目录)

我的问题是首先-是否有任何其他明显或不太明显的全局状态我应该注意(显然是环境变量,或任何全局变量)

第二,如果更多地记录这一点,或者通过任务抽象避免这一点,抽象中的“任务”,它(理论上)可以有自己的语义,就像移回工作目录一样

通过从代码中删除任何“cd()”调用,我们已经解决了产品缺陷,关键是-带有闭包抽象的cd()让我们产生了这样一种错觉,即使用它可能是安全的

即:

我们已经在端点中使用了这种代码

我对这个问题的最小复制是

function runme(path)
    mkpath(path)
    abs_path = realpath(path)
    return t = @async begin
        cd(abs_path) do
            sleep(1)
            println(path,"::",(pwd()|>splitdir)[2])
        end
    end
end

runme("a")
runme("b")
输出:(显然)


编辑:(摘要)-虽然这几乎不是一个问题-这应该是可搜索和记录的(因为它可能是同步错误的来源)

与全局变量(关于'cd()'的状态)的区别-可以使用
let
语句在闭包中捕获变量,而当前目录不能。虽然这甚至不是特定于编程语言的(而是一个操作系统进程问题),但我认为语法确实给人一种局部性的错觉(类似于python的“with”块或许多其他设备)


因此,底线是“cd”抽象不应该在任何生产实用程序中使用,除非有一天有一种方法可以将处理程序“切换回”到任务/块/闭包(类似于
最终
块)

我不清楚内部结构或特定实现,这是我个人的猜测,很高兴被julia dev纠正,但我认为任务本身并不是共享“当前目录”,而是更普遍地共享“状态”。您的示例与全局变量的行为方式相同:

testscript.jl中的
#
var=0;
函数运行时(val)
全局var=val+1;
返回t=@async begin
睡眠(1)
println(val,“:”,var);
结束
结束
runme(1)
runme(3)
REPL会话中的
#
朱莉娅>包括(“testo.jl”);
1::4
3::4
然而,(全局)状态的共享是一个特性,而不是一个bug。这与进程(julia实现真正并行的方式)相反,进程不共享状态,因此工作者之间的所有通信都需要通过套接字完成

虽然人们确实需要小心处理这个问题,但它也可能非常有用和必要。在这方面,任务(或协同程序)不用于实现并行或限制。它们是“一种协作多任务处理形式”,即在同一线程上实现多个运行操作的方法;这不是并行性,多个操作“在CPU的监督下,通过适当的调度一次运行一个”。例如,“try/catch”块(显然)是使用任务实现的

所以,为了回答第一个问题,是的,你需要知道共享状态,对于第二个问题,不,如果你以某种方式访问全局状态(当前目录是其中一个方面)的方式使用任务,我不完全确定每个任务都应该以你描述的方式有自己的语义;相反,您只需要以这样一种方式设计任务,即它们考虑到状态是共享的,并相应地采取行动

作为第二个例子,考虑两个单独的任务:“产生”需要“消耗”的输出。如果您依赖于基于全局状态的任一任务的适当消耗,那么您的任务完全有可能通过设计针对共享全局状态进行适当的行为。下面是一个简单的例子:

d=0;
功能报告()
全球d;
因为我在1:4
如果是(d);产生(“D为偶数”\n);其他的product(“D是奇数\n”);结束
结束
结束
task1=任务(报告);
task2=任务(报告);
因为我在1:4
d=i;
消费(任务1)|>打印;
消费(任务2)|>打印;
结束
D是奇数
D是奇怪的
D是平的
D是平的
D是奇怪的
D是奇怪的
D是平的
D是平的


注:最新的julia build告诉我,“生产”和“消费”正在被弃用,取而代之的是“渠道”,但想必这一点是正确的。

再次,如果你重新阅读这个问题,我知道cd()只是全局状态的一个例子,然而,这在某种程度上并不明显,因为一些库代码假定它可以使用“cd()do”块。有一件事我认为没有一个明显的——不能'Cd()'关闭-捕获Crecrect目录?这类事情可以抽象出来吗?当前目录是一个全局进程属性,因此不,如果不在任务级别模拟它,它就不能是每个任务的属性,这可能是也可能不是完全可以做到的。@oyd11正在回复,以防您没有看到Stefan的答案。此外,尽管我同意,函数在运行时的当前目录依赖于全局状态而不是本地状态这一点可能不太明显(因此,如果在任务中异步使用,则可能会发生更改),我还要说,这也不是太意外:没有理由期望它在任何时候都与环境完全隔离,仅仅因为它是异步运行的。所以,如果您知道您的函数依赖于更改目录,那么最好的做法是显式地将它们捕获到局部变量中。@oyd11不过,我很欣赏您所说的一部分,即异步调用
cd
时,“目录”的易失性值得在文档中特别指出,作为一个警告(在@async/下或在下)以及任何o
function runme(path)
    mkpath(path)
    abs_path = realpath(path)
    return t = @async begin
        cd(abs_path) do
            sleep(1)
            println(path,"::",(pwd()|>splitdir)[2])
        end
    end
end

runme("a")
runme("b")
a::b
b::b