الخيوط
التنفيذ المتزامن
الخيوط درس مجاني في Ruby Academy على CoddyKit. هذا هو الدرس 1 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Ruby Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Ruby Academy 4 دروس في المجموع.
ما هو الخيط؟
الخيط هو مسار مستقل للتنفيذ داخل برنامجك. تتيح لك Ruby تشغيل عدة خيوط بحيث تتداخل الأعمال زمنيًا.
- يعمل البرنامج الرئيسي في الخيط الرئيسي.
- تنشئ خيوطًا إضافية باستخدام
Thread.new. - تتشارك الخيوط الذاكرة نفسها، لذا يمكنها قراءة المتغيرات نفسها وكتابتها.
تكون الخيوط مثالية عندما يقضي برنامجك وقتًا في الانتظار (للشبكة أو القرص أو السكون)، إذ يمكن لخيط أن ينتظر بينما يواصل خيط آخر العمل.
إنشاء خيط
مرّر كتلة إلى Thread.new. تُشغَّل الكتلة في خيط جديد. استدعِ join للانتظار حتى يكتمل تنفيذها قبل خروج البرنامج.
t = Thread.new do
puts "Hello from the new thread"
end
t.join
puts "Main thread done"أهمية join
عندما ينتهي الخيط الرئيسي، تخرج Ruby وقد لا تنتظر الخيوط الأخرى. يحجب join الخيط المستدعي حتى يكتمل الخيط المستهدف.
من دون join، قد لا تحصل الخيط العاملة على فرصة لطباعة الناتج قبل إنهاء البرنامج.
t = Thread.new do
sleep 0.1
puts "Worker finished"
end
puts "Waiting..."
t.join
puts "All done"عدة خيوط في آن واحد
يمكنك تشغيل مجموعة من الخيوط، وتجميعها في مصفوفة، ثم استدعاء join لكل خيط منها. هذا نمط شائع لأعمال الإدخال والإخراج المتوازية تقريبًا.
threads = (1..3).map do |n|
Thread.new do
puts "Thread number " + n.to_s
end
end
threads.each(&:join)
puts "Finished all threads"مشاركة المتغيرات
تتشارك الخيوط الذاكرة. ويكون المتغير المعرّف قبل الخيط مرئيًا داخله. هذا مفيد، لكنه قد يكون خطيرًا أيضًا إذا كتب خيطان القيمة نفسها.
counter = 0
t = Thread.new do
counter += 1
end
t.join
puts "Counter is " + counter.to_sحالات التسابق
تحدث حالة التسابق عندما تتداخل تحديثات الخيوط للبيانات المشتركة، وتعتمد النتيجة على التوقيت.
- تتكون
counter += 1في الواقع من قراءة ثم جمع ثم كتابة. - يمكن لخيطين قراءة القيمة القديمة نفسها، ثم كتابة القيمة الجديدة نفسها، مما يؤدي إلى فقدان إحدى الزيادتين.
الحل هو تنسيق الوصول باستخدام قفل.
Mutex: قفل
يضمن Mutex (الاستبعاد المتبادل) تشغيل خيط واحد فقط للتعليمات البرمجية المحمية في كل مرة. ضع القسم الحرج داخل mutex.synchronize.
mutex = Mutex.new
counter = 0
threads = (1..5).map do
Thread.new do
mutex.synchronize do
counter += 1
end
end
end
threads.each(&:join)
puts "Counter is " + counter.to_sإرجاع قيمة
ينتظر Thread#value انتهاء الخيط، ثم يعيد قيمة كتلته، مثل تنفيذ join تلقائيًا مع إرجاع النتيجة.
t = Thread.new do
2 + 3
end
puts "Result is " + t.value.to_sالمتغيرات المحلية للخيوط
يمكن لكل خيط تخزين قيمه الخاصة المفهرسة برمز باستخدام Thread.current[:key]. وتبقى هذه القيم خاصة بذلك الخيط ولا تتم مشاركتها مطلقًا.
t = Thread.new do
Thread.current[:name] = "worker"
puts "Inside: " + Thread.current[:name]
end
t.joinمعالجة الاستثناءات
إذا رفع خيط خطأً، يظل الخطأ صامتًا حتى تستدعي join أو value، وعندها يُعاد رفعه. يؤدي ضبط Thread.abort_on_exception = true إلى تعطل البرنامج بأكمله فورًا عند حدوث الأخطاء، مما يساعد في تصحيح الأخطاء.
t = Thread.new do
raise "boom"
end
begin
t.join
rescue => e
puts "Caught: " + e.message
endمتى تكون الخيوط مفيدة؟
تتألق الخيوط في الأعمال المعتمدة على الإدخال والإخراج، حيث يُقضى الوقت في الانتظار. وتكون فائدتها أقل في الأعمال المعتمدة على وحدة المعالجة المركزية بسبب GVL (وسنتناوله لاحقًا).
- مناسبة: تنزيل عناوين URL متعددة وقراءة ملفات متعددة.
- محدودة الفائدة: إجراء حسابات عددية كثيفة عبر عدة أنوية.
احمِ دائمًا الحالة القابلة للتغيير والمشتركة باستخدام Mutex.
تحقق سريع
اختبر فهمك للخيوط.
مراجعة: الخيوط
تعلّمت أساسيات خيوط Ruby:
- يبدأ
Thread.newالتنفيذ المتزامن. - ينتظر
join، بينما ينتظرvalueويعيد النتيجة. - تتشارك الخيوط الذاكرة، مما قد يؤدي إلى حالات التسابق.
- يحمي
Mutexمعsynchronizeالحالة المشتركة. - تتفوق الخيوط في الأعمال المعتمدة على الإدخال والإخراج.
سنستكشف بعد ذلك سبب عجز الخيوط عن الاستفادة الكاملة من عدة أنوية لوحدة المعالجة المركزية: GVL.
الأسئلة الشائعة
هل درس «الخيوط» مجاني؟
نعم — نص درس «الخيوط» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Ruby Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Ruby Academy 4 دروس في المجموع.
ماذا ستتعلم في «الخيوط»؟
التنفيذ المتزامن تتمرن على Ruby Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ Ruby Academy؟
لا تُشترط خبرة سابقة. Ruby Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 1 من أصل 4.
كم من الوقت يستغرق درس «الخيوط»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Ruby Academy هذا؟
نعم. كل درس في Ruby Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.