Fixing precompilation hangs due to open tasks or IO
在 Julia 1.10 或更高版本中,您可能会看到以下消息:

这可能会重复。如果它继续重复而没有任何提示表明它会自行解决,您可能遇到了需要修复的“预编译挂起”问题。即使它是暂时的,您可能更希望解决它,以便用户不会受到此警告的困扰。 本页面将指导您如何分析和修复此类问题。
如果您遵循建议并按下 Ctrl-C,您可能会看到
^C Interrupted: Exiting precompilation...
  1 dependency had warnings during precompilation:
┌ Test1 [ac89d554-e2ba-40bc-bc5c-de68b658c982]
│  [pid 2745] waiting for IO to finish:
│   Handle type        uv_handle_t->data
│   timer              0x55580decd1e0->0x7f94c3a4c340此消息传达了两个关键信息:
- 在 
Test2(我们尝试使用的包)的依赖项Test1的预编译过程中发生了挂起。 - 在 
Test1的预编译过程中,Julia 创建了一个Timer对象(如果你不熟悉定时器,可以使用?Timer),该对象仍然处于打开状态;在它关闭之前,进程会挂起。 
如果这对你来说足够提示你如何创建 timer = Timer(args...),一个好的解决方案是在模块的最终 end 之前添加 wait(timer),如果 timer 最终会自行完成,或者在你需要强制关闭它时使用 close(timer)。
然而,有些情况可能并不那么简单。通常,最佳的选择是首先确定挂起是由于 Test1 中的代码还是由于 Test1 的某个依赖项:
- 选项 1: 
Pkg.add("Aqua")并使用Aqua.test_persistent_tasks。这应该帮助你识别出哪个包导致了问题,之后应遵循指令 below。如有需要,你可以创建一个PkgId,格式为Base.PkgId(UUID("..."), "Test1"),其中...来自Test1/Project.toml中的uuid条目。 - 选项 2:手动诊断挂起的来源。
 
手动诊断:
Pkg.develop("Test1")- Comment out all the code 
included or defined inTest1, except theusing/importstatements. - 尝试再次 
using Test2(或者甚至using Test1假设那也会挂起) 
现在我们来到了一个分岔路口:要么
- 挂起仍然存在,表明它是 due to one of your dependencies
 - 挂件消失,表明它是 due to something in your code。
 
Diagnosing and fixing hangs due to a package dependency
使用二分查找来识别有问题的依赖项:首先注释掉一半的依赖项,然后当你确定是哪个部分有问题时,再注释掉那一半中的一半,依此类推。(你不必将它们从项目中移除,只需注释掉 using/import 语句。)
一旦你确定了一个可疑包(在这里我们称之为 ThePackageYouThinkIsCausingTheProblem),首先尝试对该包进行预编译。如果在预编译过程中也出现挂起,继续向后追踪问题。
然而,最有可能的是 ThePackageYouThinkIsCausingTheProblem 会正常预编译。这表明问题出在函数 ThePackageYouThinkIsCausingTheProblem.__init__ 中,该函数在 ThePackageYouThinkIsCausingTheProblem 的预编译期间不会运行,但在任何加载 ThePackageYouThinkIsCausingTheProblem 的包中会运行。为了验证这个理论,设置一个最小工作示例(MWE),类似于
(@v1.10) pkg> generate MWE
  Generating  project MWE:
    MWE\Project.toml
    MWE\src\MWE.jlMWE.jl 的源代码在哪里
module MWE
using ThePackageYouThinkIsCausingTheProblem
end并且您已将 ThePackageYouThinkIsCausingTheProblem 添加到 MWE 的依赖项中。
如果该最小可重现示例(MWE)重现了挂起问题,那么你找到了罪魁祸首:ThePackageYouThinkIsCausingTheProblem.__init__ 必须在创建 Timer 对象。如果定时器对象可以安全地 close,那是一个不错的选择。否则,最常见的解决方案是在 任何 包被预编译时避免创建定时器:添加
ccall(:jl_generating_output, Cint, ()) == 1 && return nothing作为 ThePackageYouThinkIsCausingTheProblem.__init__ 的第一行,它将避免在任何旨在预编译包的 Julia 进程中进行任何初始化。
Fixing package code to avoid hangs
搜索您的包以查找暗示性词汇(这里像“计时器”),并查看您是否可以识别出问题产生的位置。请注意,像这样的定义方法
maketimer() = Timer(timer -> println("hi"), 0; interval=1)本身并不成问题:只有在模块被定义时调用 maketimer 时,它才会导致这个问题。这可能是由于顶层语句引起的,例如
const GLOBAL_TIMER = maketimer()或者它可能在一个 precompile workload 中发生。
如果你在识别因果关系时遇到困难,可以考虑进行二分查找:注释掉你包中的部分内容(或 include 行以省略整个文件),直到你缩小问题的范围。