روبي خاصية تعدد
كل برنامج يعمل على نظام هو عملية. تحتوي كل عملية واحدة أو أكثر من المواضيع.
وموضوع هو متسلسل التحكم في التدفق برنامج واحد، في وقت واحد تشغيل مواضيع متعددة في برنامج واحد تفعل أشياء مختلفة، وتسمى خيوط المعالجة المتعددة.
روبي، ونحن يمكن إنشاؤها من قبل العديد من الدرجة المواضيع الموضوع، المواضيع روبي هي خفيفة الوزن، يمكن أن يكون وسيلة فعالة لتنفيذ قانون مواز.
إنشاء موضوع روبي
لبدء موضوع جديد، يمكنك الاتصال فقط Thread.new:
# 线程 #1 代码部分 Thread.new { # 线程 #2 执行代码 } # 线程 #1 执行代码
أمثلة
يوضح المثال التالي كيفية استخدام خاصية تعدد في برنامج روبي:
#!/usr/bin/ruby def func1 i=0 while i<=2 puts "func1 at: #{Time.now}" sleep(2) i=i+1 end end def func2 j=0 while j<=2 puts "func2 at: #{Time.now}" sleep(1) j=j+1 end end puts "Started At #{Time.now}" t1=Thread.new{func1()} t2=Thread.new{func2()} t1.join t2.join puts "End at #{Time.now}"
يتم تنفيذ التعليمات البرمجية أعلاه نتيجة ل:
Started At Wed May 14 08:21:54 -0700 2014 func1 at: Wed May 14 08:21:54 -0700 2014 func2 at: Wed May 14 08:21:54 -0700 2014 func2 at: Wed May 14 08:21:55 -0700 2014 func1 at: Wed May 14 08:21:56 -0700 2014 func2 at: Wed May 14 08:21:56 -0700 2014 func1 at: Wed May 14 08:21:58 -0700 2014 End at Wed May 14 08:22:00 -0700 2014
دورة الحياة الموضوع
1 إنشاء موضوع يمكن استخدام Thread.new، يمكنك أيضا استخدام نفس تركيب Thread.start أو Thread.fork ثلاث طرق لإنشاء موضوع.
2 إنشاء موضوع دون البدء، سينفذ موضوع تلقائيا.
3، وتعرف الطبقة الموضوع طرق لمعالجة الموضوع. الموضوع من كتل التعليمات البرمجية تنفيذ Thread.new.
4، وكتلة موضوع هو قيمة العبارة الأخيرة في الموضوع، وموضوع يمكن التذرع بها طريقة، إذا تم الانتهاء من موضوع، تقوم بإرجاع قيمة موضوع، أو لا يقوم بإرجاع قيمة حتى يتم الانتهاء من الموضوع.
5 طريقة Thread.current بإرجاع كائن لتمثيل الترابط الحالي. طريقة Thread.main إرجاع موضوع الرئيسي.
6، يتم تنفيذ الطريقة التي المواضيع Thread.Join، وهذه الطريقة سوف تعليق موضوع الرئيسي حتى يتم الانتهاء من موضوع الحالي.
الدولة الموضوع
الموضوع له خمس ولايات:
الدولة الموضوع | عودة القيمة |
---|---|
تنفيذ | جولة |
نائم | نائم |
استقال | إجهاض |
إنهاء العادي | زائف |
يحدث إنهاء غير طبيعي | صفر |
المواضيع وشاذ
عندما يحدث استثناء موضوع، واعتقل لا الإنقاذ، وعادة يتم إنهاء موضوع دون سابق إنذار. ومع ذلك، في حالة انضمام # المواضيع الأخرى الموضوع لأن العلاقة كان ينتظر هذا الموضوع، ثم سيتم أيضا رفع المواضيع انتظار نفس استثناء.
begin t = Thread.new do Thread.pass # 主线程确实在等join raise "unhandled exception" end t.join rescue p $! # => "unhandled exception" end
استخدام الأساليب الثلاثة التالية، يمكنك الحصول على مترجم لوقف العملية عند إنهاء الموضوع يرجع إلى استثناء.
- يحدد النصي بدء التشغيل الخيار-d، وعملية وضع التصحيح.
- مع
Thread.abort_on_exception
تعيين علامة. - استخدام
Thread#abort_on_exception
محدد مجموعة موضوع العلم.
عند استخدام واحدة من ثلاث طرق المذكورة أعلاه، سيتم توقف مترجم كامل.
t = Thread.new { ... } t.abort_on_exception = true
تزامن الموضوع
في روبي، توفر ثلاثة بطريقة متزامنة، وهي:
1. الطبقة المزامنة تنفذ التزامن الموضوع
2. نقل البيانات التنظيمية الطبقة انتظار تنفيذ تزامن موضوع
السيطرة تزامن 3. استخدام ConditionVariable
بواسطة المزامنة الطبقة تنفذ التزامن الموضوع
على حسب الطبقة المزامنة تطبق تحكم تزامن موضوع، إذا أنت أيضا تحتاج إلى ساعة برنامج المتغيرة في مواضيع متعددة، يمكنك استخدام لقفل قفل الجزء المتغير. متاحة على النحو التالي:
#!/usr/bin/ruby require "thread" puts "Synchronize Thread" @num=200 @mutex=Mutex.new def buyTicket(num) @mutex.lock if @num>=num @num=@num-num puts "you have successfully bought #{num} tickets" else puts "sorry,no enough tickets" end @mutex.unlock end ticket1=Thread.new 10 do 10.times do |value| ticketNum=15 buyTicket(ticketNum) sleep 0.01 end end ticket2=Thread.new 10 do 10.times do |value| ticketNum=20 buyTicket(ticketNum) sleep 0.01 end end sleep 1 ticket1.join ticket2.join
يتم تنفيذ التعليمات البرمجية أعلاه نتيجة ل:
Synchronize Thread you have successfully bought 15 tickets you have successfully bought 20 tickets you have successfully bought 15 tickets you have successfully bought 20 tickets you have successfully bought 15 tickets you have successfully bought 20 tickets you have successfully bought 15 tickets you have successfully bought 20 tickets you have successfully bought 15 tickets you have successfully bought 20 tickets you have successfully bought 15 tickets sorry,no enough tickets sorry,no enough tickets sorry,no enough tickets sorry,no enough tickets sorry,no enough tickets sorry,no enough tickets sorry,no enough tickets sorry,no enough tickets sorry,no enough tickets
بالإضافة إلى استخدام قفل مقفل متغير، يمكنك أيضا استخدام try_lock متغير مقفلة، يمكنك أيضا استخدام Mutex.synchronize مزامنة الوصول إلى متغير معين.
نقل البيانات التنظيمي للطبقة قائمة الانتظار ينفذ التزامن الموضوع
الطبقة قائمة الانتظار التي تمثل الدعم طابور موضوع، قائمة الانتظار يمكن أن تكون متزامنة في نهاية الزيارة. يمكن المواضيع المختلفة استخدام فئة موحدة، ولكن لا تقلق بشأن ما إذا كانت البيانات يمكن أن تكون متزامنة في قائمة الانتظار هذه، بالإضافة إلى الحد من استخدام SizedQueue طول انتظار الطبقة
الطبقة SizedQueue يمكن أن تكون مريحة للغاية لمساعدتنا على تطوير تطبيقات مترابطة لمزامنة، وينبغي أن يضاف مشاكل التزامن إلى قائمة انتظار طويلة، كنت لا تبالي المواضيع.
المنتجين والمستهلكين الكلاسيكي:
#!/usr/bin/ruby require "thread" puts "SizedQuee Test" queue = Queue.new producer = Thread.new do 10.times do |i| sleep rand(i) # 让线程睡眠一段时间 queue << i puts "#{i} produced" end end consumer = Thread.new do 10.times do |i| value = queue.pop sleep rand(i/2) puts "consumed #{value}" end end consumer.join
إخراج البرنامج:
SizedQuee Test 0 produced 1 produced consumed 0 2 produced consumed 1 consumed 2 3 produced consumed 34 produced consumed 4 5 produced consumed 5 6 produced consumed 6 7 produced consumed 7 8 produced 9 produced consumed 8 consumed 9
المتغيرات الموضوع
موضوع يمكن أن يكون به متغير خاص وموضوع متغير الخاص موضوع الكتابة عند إنشاء موضوع. ويمكن استخدامه في نطاق الموضوع، ولكن الموضوع لا يمكن مشاركة خارجيا.
لكن في بعض الأحيان، والمتغيرات المحلية موضوع لا يحتاج موضوع آخر أو موضوع الرئيسي للوصول إلى كيفية القيام به؟ روبي يسمح لهم لخلق وتقدم الموضوع من قبل اسم المتغير، ينظر إلى موضوع كما نمط مماثل جدول تجزئة التجزئة. بواسطة [] = كتبه [] قراءة البيانات. ونحن ننظر في التعليمة البرمجية التالية:
#!/usr/bin/ruby count = 0 arr = [] 10.times do |i| arr[i] = Thread.new { sleep(rand(0)/10.0) Thread.current["mycount"] = count count += 1 } end arr.each {|t| t.join; print t["mycount"], ", " } puts "count = #{count}"
تشغيل التعليمات البرمجية أعلاه الإخراج هو:
8, 0, 3, 7, 2, 1, 6, 5, 4, 9, count = 10
اكتمال ينتظر موضوع الرئيسية لتنفيذ موضوع الطفل، ومن ثم إخراج كل قيمة. .
الأولوية الموضوع
الأولوية الموضوع هو العامل الرئيسي الذي يؤثر على جدولة موضوع. وتشمل العوامل الأخرى طول الفترة الزمنية لأداء وحدة المعالجة المركزية موضوع جدولة حزم وهلم جرا.
يمكنك استخدام Thread.priority الحصول الأولوية لموضوع واستخدام Thread.priority = طريقة لضبط أولوية الموضوع.
التخلف الأولوية لموضوع بنتيجة 0. تنفيذ أسرع من أولوية أعلى.
والموضوع يمكن الوصول إلى كافة البيانات في نطاق من تلقاء نفسها، ولكن إذا كان هناك مواضيع أخرى تحتاج إلى الوصول إلى البيانات في موضوع يجب أن يكون كيف نفعل ذلك؟ توفر الطبقة موضوع البيانات موضوع الوصول بعضها البعض، يمكنك ببساطة وضع موضوع كجدول تجزئة، ويمكن استخدامها في أي موضوع [] البيانات = الكتابة، استخدم [] قراءة البيانات.
athr = Thread.new { Thread.current["name"] = "Thread A"; Thread.stop } bthr = Thread.new { Thread.current["name"] = "Thread B"; Thread.stop } cthr = Thread.new { Thread.current["name"] = "Thread C"; Thread.stop } Thread.list.each {|x| puts "#{x.inspect}: #{x["name"]}" }
يمكننا أن نرى، في موضوع كجدول تجزئة، استخدم [] و [] = طريقة، حققنا تبادل البيانات بين المواضيع.
مزامنة الموضوع
مزامنة (استبعاد Mutal = مزامنة) هي طريقة لمتعددة الخيوط البرمجة، آلية لمنع اثنين من المواضيع في وقت واحد على نفس الموارد العامة (مثل المتغيرات العالمية) القراءة والكتابة.
أمثلة على عدم استخدام Mutax
#!/usr/bin/ruby require 'thread' count1 = count2 = 0 difference = 0 counter = Thread.new do loop do count1 += 1 count2 += 1 end end spy = Thread.new do loop do difference += (count1 - count2).abs end end sleep 1 puts "count1 : #{count1}" puts "count2 : #{count2}" puts "difference : #{difference}"
تشغيل إخراج المثال أعلاه هو:
count1 : 9712487 count2 : 12501239 difference : 0
مثال Mutax
#!/usr/bin/ruby require 'thread' mutex = Mutex.new count1 = count2 = 0 difference = 0 counter = Thread.new do loop do mutex.synchronize do count1 += 1 count2 += 1 end end end spy = Thread.new do loop do mutex.synchronize do difference += (count1 - count2).abs end end end sleep 1 mutex.lock puts "count1 : #{count1}" puts "count2 : #{count2}" puts "difference : #{difference}"
تشغيل إخراج المثال أعلاه هو:
count1 : 1336406 count2 : 1336406 difference : 0
مأزق
أكثر من وحدتين العملية، كلا الجانبين ينتظرون البعض لإيقاف تشغيل، للحصول على موارد النظام، ولكن ليس الخروج المبكر الحزب، وهذا ما يسمى حالة توقف تام.
على سبيل المثال، P1 العملية تستغرق متابعة العرض، في حين يجب أن تستخدم الطابعة، واحتلت الطابعة التي P2 العملية، يجب P2 أيضا استخدام جهاز العرض، وبالتالي تشكيل الجمود.
عندما نستخدم المزامنة كائن يحتاج إلى عناية موضوع الجمود.
أمثلة
#!/usr/bin/ruby require 'thread' mutex = Mutex.new cv = ConditionVariable.new a = Thread.new { mutex.synchronize { puts "A: I have critical section, but will wait for cv" cv.wait(mutex) puts "A: I have critical section again! I rule!" } } puts "(Later, back at the ranch...)" b = Thread.new { mutex.synchronize { puts "B: Now I am critical, but am done with cv" cv.signal puts "B: I am still critical, finishing up" } } a.join b.join
إخراج المثال أعلاه هو:
A: I have critical section, but will wait for cv (Later, back at the ranch...) B: Now I am critical, but am done with cv B: I am still critical, finishing up A: I have critical section again! I rule!
أسلوب فئة الموضوع
كامل الموضوع (موضوع) أسلوب فئة على النحو التالي:
لا. | طريقة الوصف |
---|---|
1 | Thread.abort_on_exception وإذا كان صحيحا، مرة واحدة إنهاء الموضوع بسبب استثناء، سيتم مقاطعة مترجم كامل. القيمة الافتراضية هي كاذبة، وهذا هو، في ظل الظروف العادية، في حالة حدوث استثناء موضوع والاستثناء ليس الموضوع # انضمام وغيرها من الكشف، سيتم إنهاء موضوع دون سابق إنذار. |
2 | Thread.abort_on_exception = إذا تم تعيين إلىصحيح،مرة واحدة إنهاء الموضوع بسبب استثناء، سيتم مقاطعة مترجم كامل. يعود الدولة الجديدة |
3 | Thread.critical إرجاع قيمة منطقية. |
4 | Thread.critical = عندما تكون القيمة الحقيقية، لن يتم تبديل الموضوع. إذا كان الترابط الحالي لتعليق (توقف) أو إشارة (إشارة) تدخل، وسيتم تغيير قيمته تلقائيا إلى false. |
5 | Thread.current إرجاع موضوع تشغيل الحالي (موضوع الحالي). |
6 | Thread.exit أن ينهي مؤشر الترابط الحالي. إرجاع الترابط الحالي. إذا كان الترابط الحالي هو الخيط الوحيد، وذلك باستخدام الخروج (0) لإنهاء عملها. |
7 | Thread.fork {كتلة} كما هو الحال مع Thread.new توليد المواضيع. |
8 | Thread.kill (aThread) إنهاء موضوع على التوالي. |
9 | Thread.list بإرجاع صفيف من موضوع الحية قيد التشغيل أو دولة مع وقف التنفيذ. |
10 | Thread.main عودة إلى موضوع الرئيسي. |
11 | Thread.new ([ARG] *) { | وسائط | كتلة} توليد موضوع والبدء في التنفيذ. سيتم تمرير عدد سليمة إلى كتلة، وهذا يمكن البدء في نشر موضوع في نفس الوقت، سيتم تمرير القيمة إلى المتغيرات المحلية المتأصلة في الموضوع. |
12 | Thread.pass الحق في تشغيل المواضيع الأخرى. وهو لا يغير حالة المواضيع على التوالي، ولكن ستسلم السيطرة على المواضيع الأخرى يمكن تشغيل (جدولة موضوع الصريحة). |
13 | Thread.start ([وسائط] *) { | وسائط | كتلة} توليد موضوع والبدء في التنفيذ. سيتم تمرير عدد سليمة إلى كتلة، وهذا يمكن البدء في نشر موضوع في نفس الوقت، سيتم تمرير القيمة إلى المتغيرات المحلية المتأصلة في الموضوع. |
14 | Thread.stop وعلقت الترابط الحالي حتى المواضيع الأخرى تشغيل طريقة تستيقظ مرة أخرى حتى الخيط. |
موضوع أسلوب مثيل
ويدعو المثال التالي أسلوب مثيل موضوع الانضمام:
#!/usr/bin/ruby thr = Thread.new do # 实例化 puts "In second thread" raise "Raise exception" end thr.join # 调用实例化方法 join
وهنا لائحة كاملة من الأمثلة على طريقة:
لا. | طريقة الوصف |
---|---|
1 | عبتي [اسم] ازالة الموضوع من اسم المقابلة لبيانات الكامنة. اسم يمكن أن يكون سلسلة أو رمز. إذا لم يكن اسم تتوافق مع البيانات، فإنها ترجع شيء. |
2 | عبتي [اسم] = تعيين قيمة اسم موضوع في البيانات مميزة المقابل، يمكن أن يكون اسم سلسلة أو رمز. إذا تم تعيين إلى لا شيء، ويزيل البيانات المناظرة في هذا الموضوع. |
3 | thr.abort_on_exception إرجاع قيمة منطقية. |
4 | thr.abort_on_exception = إذا قيمتها الحقيقية، ثم مرة واحدة إنهاء الموضوع بسبب استثناء، سيتم مقاطعة مترجم كامل. |
5 | thr.alive؟ إذا كان موضوع هو "العيش"، فإنها ترجع صحيح. |
6 | thr.exit إنهاء موضوع على التوالي. يعود النفس. |
7 | thr.join يعلق الترابط الحالي حتى على المدى النفس حتى إنهاء الموضوع. وإذا كانت النفس بسبب إنهاء غير طبيعي، فإن الترابط الحالي يؤدي نفس استثناء. |
8 | thr.key؟ إذا كان اسم المقابلة لبيانات الكامنة المواضيع المحددة، ثم يعود صحيح |
9 | thr.kill Thread.exit ماشابهذلك. |
10 | thr.priority يعود الأولوية لمؤشر الترابط. إن الأولوية الافتراضية هي 0. أكبر قيمة، وارتفاع الأولوية. |
11 | thr.priority = تحديد أولوية الموضوع. يمكنك أيضا تعيين إلى سلبية. |
12 | thr.raise (anException) ضمن هذا الموضوع القيت قسرا. |
13 | thr.run إعادة قيد الانتظار (توقف) موضوع، والفرق هو أنه مع التنبيه ستجري موضوع التحول فورا. إذا كنت تستخدم هذه الطريقة لمعالجة سيتم رفع القتلى استثناء ThreadError. |
14 | thr.safe_level يعود مستوى الأمن الذاتي. Safe_level في موضوع $ الحالي SAFE نفسه. |
15 | thr.status باستخدام سلسلة "المدى"، "النوم" أو "اجهاض" للإشارة إلى حالة من موضوع العيش إذا تم إنهاء الموضوع بشكل عادي، ثم فإنها ترجع كاذبة. Ruoyin لإنهاء غير طبيعي، ثم يعود لا شيء. |
16 | thr.stop؟ إذا تم إنهاء موضوع الدولة (ميتا) أو تعليق (توقف)، والعودة الحقيقية. |
17 | thr.value انتظر حتى إنهاء موضوع الذاتي (أي ما يعادل الانضمام)، إرجاع قيمة كتلة من موضوع إذا كانت المواضيع تشغيل تحدث أثناء غير طبيعي، سيتم رفع الاستثناء مرة أخرى. |
18 | thr.wakeup وعلقت الدولة (وقف) من موضوع إلى الدولة جاهزة (المدى)، إذا يتم تنفيذ الأسلوب على موضوع ميت سترفع ThreadError استثناء. |