为什么多处理Julia会破坏我的模块导入



我的团队正在尝试运行一个具有多处理功能并使用julia -p #参数的库(带有JuMP的Cbc(。我们的代码在julia包中,因此我们可以使用julia --project很好地运行我们的代码,它只运行一个进程。尝试同时指定两者,但是julia --project -p 8破坏了我们运行项目的能力,因为在之后运行using PackageName会导致错误。我们还打算使用PackageCompiler库来编译它,因此让它与项目一起工作是必要的。

我们将项目放在一个文件夹中,该文件夹包含src目录、project.toml和Manifest.tomlsrc包含:main.jl和Solver.jl

Project.toml包含:

name = "Solver"
uuid = "5a323fe4-ce2a-47f6-9022-780aeeac18fe"
authors = ["..."]
version = "0.1.0"

通常情况下,我们的项目以这种方式(单线程(运行良好:

julia --project
julia> using Solver
julia> include("src/main.jl")

如果在启动Julia时添加-p 8参数,则在键入using Solver:时会出现错误

ERROR: On worker 2:
ArgumentError: Package Solver [5a323fe4-ce2a-47f6-9022-780aeeac18fe] is required but does not seem to be installed:
- Run `Pkg.instantiate()` to install all recorded dependencies.

我们已经尝试运行using Pkg; Pkg.instantiate(); using Solver,但这没有帮助,因为稍后会发生另一个错误(在include("src/main.jl")步骤(:

ERROR: LoadError: On worker 2:
ArgumentError: Package Solver not found in current path:
- Run `import Pkg; Pkg.add("Solver")` to install the Solver package.

然后遵循这个建议会产生另一个错误:

ERROR: The following package names could not be resolved:
* Solver (not found in project, manifest or registry)
Please specify by known `name=uuid`.

为什么此模块导入在单进程模式下工作良好,而在-p 8下工作不正常?

提前感谢您的考虑

首先需要注意的是,您不是在使用多线程并行,而是在使用分布式并行。当您使用-p 2启动时,您正在启动两个不共享同一内存的不同进程。此外,项目只在主进程中加载,这就是为什么其他进程看不到项目中的内容。您可以在官方文档中了解更多关于Julia提供的各种并行性的信息。

要在所有工作线程中加载环境,可以将其添加到文件的开头。

using Distributed
addprocs(2; exeflags="--project")
@everywhere using Solver
@everywhere include("src/main.jl")

并删除用于启动julia的行的-p 2部分。这将在所有进程上加载项目。@everywhere宏用于指示执行给定任务的所有进程。这部分文档对此进行了解释。

然而,请注意,并行性并不是自动工作的,因此,如果您的软件没有考虑到分布式并行性,那么它可能不会从新启动的Worker中获得任何好处。

当存在未编译的模块并且多个并行进程试图同时编译它以供首次使用时,Julia会出现问题。

因此,如果你在一台机器上跨多个进程运行自己的模块,你总是需要以以下方式运行(这假设Julia进程在你的项目所在的同一文件夹中运行(:

using Distributed, Pkg
@everywhere using Distributed, Pkg
Pkg.activate(".")
@everywhere Pkg.activate(".")
using YourModuleName
@everywhere using YourModuleName

我认为这种方法没有记录在案,但我在实验中发现它是最健壮的。如果你有时(不总是!(不使用我的模式,就会发生编译器追逐,而且往往会发生奇怪的事情。

请注意,如果您正在运行分布式集群,则需要修改上面的代码,以便在每个节点的单个工作线程上运行初始化,而不是在所有工作线程上。

最新更新