Fixing precompilation hangs due to open tasks or IO

في جوليا 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

تحتوي هذه الرسالة على نقطتين رئيسيتين:

  • يحدث التعليق أثناء ما قبل التجميع لـ Test1، وهو اعتماد لـ Test2 (الحزمة التي كنا نحاول تحميلها باستخدام using Test2)
  • خلال مرحلة ما قبل التجميع لـ Test1، أنشأت جوليا كائن Timer (استخدم ?Timer إذا كنت غير مألوف بـ Timers) والذي لا يزال مفتوحًا؛ حتى يتم إغلاقه، ستظل العملية متوقفة.

إذا كانت هذه تلميحًا كافيًا لك لتكتشف كيف يتم إنشاء timer = Timer(args...)، فإن إحدى الحلول الجيدة هي إضافة wait(timer) إذا كان timer ينتهي في النهاية من تلقاء نفسه، أو close(timer) إذا كنت بحاجة إلى إغلاقه بالقوة، قبل النهاية النهائية للوحدة.

ومع ذلك، هناك حالات قد لا تكون بهذه السهولة. عادةً ما تكون أفضل خيار هو البدء بتحديد ما إذا كان التوقف ناتجًا عن الكود في Test1 أو ما إذا كان ناتجًا عن أحد تبعيات Test1:

  • الخيار 1: Pkg.add("Aqua") واستخدم Aqua.test_persistent_tasks. يجب أن يساعدك هذا في تحديد الحزمة التي تسبب المشكلة، بعد ذلك يجب اتباع التعليمات below. إذا لزم الأمر، يمكنك إنشاء PkgId كـ Base.PkgId(UUID("..."), "Test1")، حيث يأتي ... من إدخال uuid في Test1/Project.toml.
  • الخيار 2: تشخيص مصدر التوقف يدويًا.

لتشخيص يدوي:

  1. Pkg.develop("Test1")
  2. Comment out all the code included or defined in Test1, except the using/import statements.
  3. حاول using Test2 (أو حتى using Test1 على افتراض أن ذلك يتسبب في تعليق أيضًا) مرة أخرى

الآن نصل إلى مفترق طرق: إما

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.jl

أين يوجد كود المصدر لـ MWE.jl

module MWE
using ThePackageYouThinkIsCausingTheProblem
end

وقد أضفت ThePackageYouThinkIsCausingTheProblem إلى تبعيات MWE.

إذا كان هذا المثال البسيط يعيد إنتاج التوقف، فقد وجدت الجاني: ThePackageYouThinkIsCausingTheProblem.__init__ يجب أن يكون قد أنشأ كائن Timer. إذا كان من الممكن إغلاق كائن المؤقت بأمان، فهذه خيار جيد. خلاف ذلك، فإن الحل الأكثر شيوعًا هو تجنب إنشاء المؤقت أثناء أي حزمة يتم تجميعها مسبقًا: أضف

ccall(:jl_generating_output, Cint, ()) == 1 && return nothing

كالسطر الأول من ThePackageYouThinkIsCausingTheProblem.__init__، وسيتجنب القيام بأي تهيئة في أي عملية جوليا الغرض منها تجميع الحزم مسبقًا.

Fixing package code to avoid hangs

ابحث في حزمة الخاص بك عن كلمات توحي (هنا مثل "مؤقت") وانظر إذا كنت تستطيع تحديد مكان المشكلة التي يتم إنشاؤها. لاحظ أن تعريف الطريقة مثل

maketimer() = Timer(timer -> println("hi"), 0; interval=1)

ليس مشكلة في حد ذاته: يمكن أن يسبب هذه المشكلة فقط إذا تم استدعاء maketimer أثناء تعريف الوحدة. قد يحدث هذا من عبارة على المستوى الأعلى مثل

const GLOBAL_TIMER = maketimer()

أو قد يحدث بشكل محتمل في precompile workload.

إذا كنت تواجه صعوبة في تحديد الخطوط المسببة، ففكر في إجراء بحث ثنائي: قم بالتعليق على أقسام من حزمةك (أو استخدم include لاستبعاد ملفات كاملة) حتى تقلل نطاق المشكلة.