ReadyToRun والترجمة متعددة المستويات
افهموا الترجمة المسبقة ReadyToRun، وترجمة JIT متعددة المستويات، وتحسين PGO (التحسين الموجّه بالملف التعريفي) في .NET.
ReadyToRun والترجمة متعددة المستويات درس مجاني في C# Academy على CoddyKit. هذا هو الدرس 3 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في C# Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة C# Academy 4 دروس في المجموع.
JIT وR2R والترجمة متعددة المستويات
يستخدم .NET عدة استراتيجيات للترجمة لتحقيق توازن بين سرعة بدء التشغيل ومعدل المعالجة الأقصى. ويساعدكم فهم JIT وReadyToRun والترجمة متعددة المستويات على اختيار الإعدادات المناسبة لعبء العمل.
كيف يعمل JIT
يحوّل مترجم Just-in-Time (JIT) بايت كود IL إلى كود آلة أصلي عند استدعاء كل أسلوب للمرة الأولى. ويضيف ذلك زمن تأخير إلى الاستدعاء الأول، لكنه ينتج كودًا محسنًا بدرجة كبيرة للجهاز الذي يشغّل التطبيق.
// What happens at runtime:
// 1. App starts — methods are stubs pointing to the JIT
// 2. First call to MyMethod() → JIT compiles IL → native x64 code
// 3. Subsequent calls → native code runs directly (no JIT overhead)
// Startup cost: each method's first call takes microseconds for JIT
// Peak performance: excellent — JIT knows the actual CPU features
// .NET 9 JIT optimizations applied automatically:
// - Inlining
// - Loop unrolling
// - Escape analysis
// - SIMD vectorization
// - Profile-Guided Optimization (PGO)الترجمة باستخدام ReadyToRun (R2R)
يترجم ReadyToRun (R2R) تجميعاتكم مسبقًا إلى كود أصلي وقت النشر. ويبدأ التطبيق بسرعة أكبر لأن عمل JIT يكون قد أُنجز مسبقًا، مقابل زيادة الحجم على القرص.
// Enable R2R in .csproj:
<PropertyGroup>
<PublishReadyToRun>true</PublishReadyToRun>
<!-- Optional: composite R2R — whole app in one native image -->
<PublishReadyToRunComposite>true</PublishReadyToRunComposite>
</PropertyGroup>
// Publish:
dotnet publish -c Release -r linux-x64 --self-contained
// Benefits:
// - Startup time improvement: ~20-30% faster than JIT-only
// - No runtime required (self-contained)
// Trade-off:
// - Larger binary (IL + R2R code both stored)
// - Publish takes longer (cross-gen2 runs at publish time)R2R في مقابل Native AOT
يظل IL مضمّنًا مع الكود الأصلي عند استخدام R2R، كما تظل بيئة تشغيل .NET مطلوبة. أما Native AOT فيزيل IL وبيئة التشغيل بالكامل. اختاروا الحل وفقًا لمتطلبات النشر.
// ReadyToRun:
// ✓ Still ships IL (fallback JIT for dynamically-generated code)
// ✓ Supports full reflection
// ✓ .NET runtime required on target
// ✓ Startup: ~30% faster than JIT
// Size: medium (IL + native)
// Native AOT:
// ✓ No IL, no runtime needed on target
// ✓ Startup: ~36x faster than JIT
// ✗ No reflection (must use source generators)
// ✗ Trimming limitations
// Size: smallest
// JIT only:
// ✓ Full reflection, no limitations
// ✓ Best peak throughput via PGO
// ✗ Slowest startupالترجمة متعددة المستويات
تكون الترجمة متعددة المستويات مفعّلة افتراضيًا في .NET. تبدأ الأساليب في المستوى 0 (ترجمة سريعة)، ثم يُعاد ترجمة الأساليب كثيرة الاستخدام في المستوى 1 (تحسين كامل) في الخلفية.
// Tiered compilation lifecycle:
// Tier 0: fast JIT with minimal optimization
// → method is callable in ~100 microseconds
// After ~30 calls (configurable): marked as "hot"
// Tier 1: full JIT with all optimizations + PGO
// → background thread re-compiles the method
// → future calls use optimized native code
// Usually transparent — you don't need to configure it
// Disable (rarely needed, only for debugging JIT issues):
// DOTNET_TieredCompilation=0
// Disable tiered PGO if benchmarking:
// DOTNET_TieredPGO=0التحسين الموجّه بالملف التعريفي (PGO)
يتضمن .NET 8+ ميزة Dynamic PGO افتراضيًا. تجمع بيئة التشغيل بيانات ملف تعريف الاستدعاءات في المستوى 0، ثم تستخدم هذا الملف لإنشاء كود متخصص بدرجة كبيرة في المستوى 1 للمسارات كثيرة الاستخدام.
// PGO automatically specializes code like:
// Before PGO (generic virtual dispatch):
void Process(IAnimal animal) => animal.Speak();
// → runtime checks type on every call
// After PGO (type-specialized inline):
void Process(IAnimal animal)
{
if (animal is Dog) { /* inlined Dog.Speak() */ }
else if (animal is Cat){ /* inlined Cat.Speak() */ }
else animal.Speak(); // slow path
}
// Enabled by default in .NET 8+
// Verify:
// DOTNET_ReadyToRun=0
// DOTNET_TieredCompilation=1 (default)
// DOTNET_TieredPGO=1 (default .NET 8+)خطافات بدء التشغيل
تتيح خطافات بدء التشغيل (DOTNET_STARTUP_HOOKS) حقن كود قبل تشغيل Main، وهو ما يفيد في التشخيص أو تجاوزات الإعداد أو إضافة أدوات القياس دون تعديل كود التطبيق.
// Create a hook class:
public class StartupHook
{
public static void Initialize()
{
Console.WriteLine("[StartupHook] Initializing before Main");
// e.g., register telemetry, inject config overrides
Environment.SetEnvironmentVariable("FEATURE_FLAG", "1");
}
}
// Compile to a DLL and set the env var:
export DOTNET_STARTUP_HOOKS=/path/to/MyHook.dll
// Then run your app normally:
dotnet run
// [StartupHook] Initializing before Main
// [Your App Output]إعدادات بيئة التشغيل
تتيح بيئة تشغيل .NET متغيرات البيئة وإعدادات runtimeconfig.json لضبط GC ومجمّع مؤشرات الترابط وسلوك JIT دون إجراء تغييرات على الكود.
// runtimeconfig.template.json (baked into app at publish):
{
"configProperties": {
"System.GC.Server": true, // server GC (multi-core)
"System.GC.Concurrent": true, // background GC
"System.GC.HeapHardLimit": 536870912, // 512 MB hard limit
"System.Threading.ThreadPool.MinThreads": 20,
"System.Threading.ThreadPool.MaxThreads": 200,
"System.Runtime.TieredCompilation": true
}
}
// Environment variable overrides (useful in containers):
// DOTNET_GCHeapHardLimit=536870912
// DOTNET_ThreadPool_UnfairSemaphoreSpinLimit=70
// DOTNET_GCConserve=1 // reduce memory at cost of throughputCrossgen2 والصور المركبة
Crossgen2 هي الأداة التي تنتج صور R2R. وتترجم R2R المركبة تطبيقًا كاملًا، أي التطبيق مع إطار العمل، مسبقًا إلى صورة أصلية مشتركة واحدة لتحقيق أفضل بدء تشغيل ممكن.
// Composite R2R: compile app + framework into one native image
<PropertyGroup>
<PublishReadyToRun>true</PublishReadyToRun>
<PublishReadyToRunComposite>true</PublishReadyToRunComposite>
</PropertyGroup>
// Normal R2R includes multiple images per assembly
// Composite merges them → fewer file reads at startup
// Manual crossgen2 invocation:
dotnet tool install -g dotnet-crossgen2
crossgen2 \
--composite \
--out composite.dll \
MyApp.dll framework/System.Runtime.dll
// Inspect R2R content:
dotnet-ildasm --methodheader MyApp.dll | grep --color R2Rمن الواقع العملي: ضبط بدء تشغيل ASP.NET Core
قائمة بالإعدادات العملية اللازمة لتعظيم أداء بدء التشغيل في خدمة ASP.NET Core مخصصة للإنتاج.
// .csproj:
<PublishReadyToRun>true</PublishReadyToRun> // pre-JIT at publish
<PublishReadyToRunComposite>true</PublishReadyToRunComposite>
<TieredCompilation>true</TieredCompilation> // default
// Program.cs — avoid startup work:
// ✓ Use AddHealthChecks() NOT AddDbContextCheck() for faster probe
// ✓ Lazy-initialize expensive singletons
// ✓ Don't await long tasks in Program.cs before app.Run()
// Container settings:
// DOTNET_GCServer=1 → server GC for multi-core pods
// DOTNET_GCHeapHardLimit=536870912 → prevent OOM in constrained pods
// DOTNET_ThreadPool_MinThreads=20 → reduce thread starvation under burst load
// Measure startup:
// app.MapGet("/startup-time",
// () => $"Ready in: {Stopwatch.GetElapsedTime(startTimestamp).TotalMs}ms");تحقق سريع
ما الفرق الأساسي بين ReadyToRun (R2R) وNative AOT؟
مراجعة: ReadyToRun والترجمة متعددة المستويات
أهم النقاط:
- الترجمة متعددة المستويات: الإعداد الافتراضي في .NET — المستوى 0 (ترجمة سريعة) ← المستوى 1 (تحسين + PGO)
- Dynamic PGO: الإعداد الافتراضي في .NET 8+ — تنشئ بيئة التشغيل ملفات تعريف للمسارات كثيرة الاستخدام وتخصص كود المستوى 1
- ReadyToRun: يترجم مسبقًا وقت النشر؛ بدء تشغيل أسرع بنحو 30%؛ لا يزال يحتاج إلى بيئة التشغيل؛ ويدعم الانعكاس
- Native AOT: بلا IL وبلا بيئة تشغيل؛ بدء تشغيل أسرع بنحو 36 مرة؛ لا يدعم الانعكاس؛ ويقدم أصغر ملف ثنائي
- اضبطوا الإعدادات عبر
runtimeconfig.jsonومتغيرات البيئة، بما في ذلك إعدادات GC ومجمّع مؤشرات الترابط وJIT - تدمج R2R المركبة التطبيق وإطار العمل في صورة أصلية واحدة لتحقيق أفضل بدء تشغيل
الأسئلة الشائعة
هل درس «ReadyToRun والترجمة متعددة المستويات» مجاني؟
نعم — نص درس «ReadyToRun والترجمة متعددة المستويات» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة C# Academy، انتقل إلى CoddyKit PRO. تتضمن دورة C# Academy 4 دروس في المجموع.
ماذا ستتعلم في «ReadyToRun والترجمة متعددة المستويات»؟
افهموا الترجمة المسبقة ReadyToRun، وترجمة JIT متعددة المستويات، وتحسين PGO (التحسين الموجّه بالملف التعريفي) في .NET. تتمرن على C# Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ C# Academy؟
لا تُشترط خبرة سابقة. C# Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 3 من أصل 4.
كم من الوقت يستغرق درس «ReadyToRun والترجمة متعددة المستويات»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس C# Academy هذا؟
نعم. كل درس في C# Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- الترجمة إلى Native AOT
- القصّ وقيود Reflection
- ReadyToRun والترجمة متعددة المستويات
- قياس الأداء باستخدام BenchmarkDotNet