消除由于打开任务或I/O而导致的预编译冻结
该页面正在翻译中。 |
在Julia1.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
这条消息突出了两个关键点。:
-
挂起发生在`Test1`的预编译期间,`Test2’的依赖关系(我们尝试使用`using Test2’下载的软件包);
-
在`Test1`的预编译过程中,Julia创建了一个`Timer’对象(使用'?定时器`,如果你不熟悉定时器),这仍然是开放的。 该过程将挂起,直到它关闭。
如果这足以理解`timer=Timer(args...),如果`计时器`最终自行完成,建议添加`等待(计时器)
,或者`关闭(计时器),如果您需要在模块的最终终止(`结束
)之前强制关闭。
然而,在某些情况下,它并不那么简单。 通常最好首先确定挂起是否与Test1中的代码或Test1依赖项之一相关。:
-
备选案文1。 'Pkg。添加("Aqua"’并使用https://juliatesting.github.io/Aqua …jl/dev/#Aqua。test_persistent_tasks-元组{Base.PkgId}['水。test_persistent_tasks']。 这将帮助您确定导致问题的软件包,然后运行 见下文说明。 如有必要,您可以将`PkgId’创建为'+Base。PkgId(UUID("。.."),"Test1")+
,其中
。..'取自’Test1/Project中的’uuid’条目。汤姆。 -
备选案文2。 手动诊断挂起的原因。
执行手动诊断:
-
'Pkg。开发("Test1")`
-
在`using/import’语句的上下文中注释掉所有包含(
include
)或在`Test1`中定义的代码。 -
再次尝试’使用Test2'(或者甚至`使用Test1',如果它也冻结)。
现在我们站在一个十字路口:要么
-
盘旋继续,表明它是 与您的一个依赖项相关,
-
或者挂起消失,表明它正在发生。 因为你的代码中的东西。
诊断和消除由于包依赖而导致的冻结
使用二进制搜索来识别有问题的依赖关系:首先注释掉一半的依赖关系,然后,当你确定哪一个是负责任的,注释掉那一半的一半,等等。 (您不必将它们从项目中删除,只需注释掉’using'/`import’语句即可)。
确定了可疑的问题(在这里我们将其称为’ThePackageYouThinkIsCausingTheProblem'`,首先尝试预编译此包。 如果它也在预编译期间冻结,请继续以相反的方向寻找问题。
但是,最有可能的是,ThePackageYouThinkIsCausingTheProblem’的预编译将正常执行。 这表明问题出在函数’ThePackageYouThinkIsCausingTheProblem。__init__
,在`ThePackageYouThinkIsCausingTheProblem’的预编译期间不执行,而是在任何加载`ThePackageYouThinkIsCausingTheProblem’的包中执行。 为了测试这个理论,创建一个最小工作示例(MWE),如下所示:
(@v1.10) pkg> generate MWE
Generating project MWE:
MWE\Project.toml
MWE\src\MWE.jl
其中’MWE的源代码。jl’看起来像
module MWE
using ThePackageYouThinkIsCausingTheProblem
end
并且您将`ThePackageYouThinkIsCausingTheProblem’添加到MWE依赖项中。
如果这个MWE再现了悬挂,你已经找到了罪魁祸首’ThePackageYouThinkIsCausingTheProblem。__init__`应该创建一个’Timer’对象。 如果timer对象可以安全关闭('close'),这是一个很好的选择。 否则,最常见的解决方案是在预编译任何包时不创建计时器:添加
ccall(:jl_generating_output, Cint, ()) == 1 && return nothing
作为第一行,'ThePackageYouThinkIsCausingTheProblem。__init__`,这将避免在任何旨在预编译包的Julia进程中进行初始化。
修复包代码以防止冻结
查找包中的前导词(例如,计时器),并尝试确定问题发生的位置。 请注意,该方法的_definition_的形式
maketimer() = Timer(timer -> println("hi"), 0; interval=1)
它本身没有问题:只有在模块定义期间调用`maketimer',它才会导致这个问题。 这可能来自顶级运营商,例如
const GLOBAL_TIMER = maketimer()
或者它可能发生在https://github.com/JuliaLang/PrecompileTools …jl[预编译工作量]。
如果您很难识别因果字符串,请使用二进制搜索:注释掉包的部分(或包含(include
)字符串以跳过整个文件),直到减少问题的规模。