الفرق بين المراجعتين لصفحة: «Ruby/Kernel/select»

من موسوعة حسوب
< Ruby‏ | Kernel
أنشأ الصفحة ب'<noinclude>{{DISPLAYTITLE: التابع <code>select‎</code> الخاص بالصنف <code>Kernel</code> في روبي}}</noinclude> تصنيف: Ruby تصني...'
 
لا ملخص تعديل
سطر 3: سطر 3:
[[تصنيف: Ruby Method]]
[[تصنيف: Ruby Method]]
[[تصنيف: Ruby Kernel]]
[[تصنيف: Ruby Kernel]]
يستدعي select(2). ويقوم بمراقبة المصفوفة المعطاة المكونة من كائنات <code>IO</code>، وينتظر حتى يكون أحد كائنات <code>IO</code> جاهزًا للقراءة ، وجاهزا للكتابة، ويكون لها استثناءات معلقة (pending exceptions) على التوالي، ثم يعيد مصفوفة تحتوي على مصفوفات مكونة من تلك كائنات <code>IO</code> السابقة.  ستُعاد القيمة <code>nil</code> إذا تم إعطاء قيمة للوسيط الاختياري timeout، ولم يكن هناك أي كائن <code>IO</code> جاهزًا خلال timeout ثانية.
يستدعي هذا التابع نظام الاستدعاء <code>select(2)</code>‎. ويقوم بمراقبة (monitors) المصفوفات المعطاة المكونة من كائنات <code>IO</code>، وينتظر حتى يكون أحد كائنات <code>IO</code> جاهزًا للقراءة ، وللكتابة، ويكون لها استثناءات معلقة (pending exceptions) تواليًا، ثم يعيد مصفوفة تحتوي على مصفوفات مكونة من كائنات <code>IO</code> السابقة.   
تراقب <code>IO.select</code> المخزن المؤقت (buffer) لكائنات <code>IO</code> لاختبار قابليتها للقراءة. إذا لم يكن المخزن المؤقت <code>IO</code> فارغًا، فسيقوم <code>IO.select</code> على الفور بالابلاغ عن جاهزية القراءة. هذا المراقبة لا تشمل إلا <code>IO</code> كائنا. ولا تحدث للكائنات شبيهة IO مثل OpenSSL :: SSL :: SSLSocket.
 
أفضل طريقة لاستخدام <code>IO.select</code> هي باستدعائها بعد توابع غير مُعطّلة (nonblocking methods) مثل <code>read_nonblock</code> و <code>write_nonblock</code> ، وغيرهما. تطلق التوابع استثناء، والذي يُوسّع بواسطة <code>IO::WaitReadable</code> أو <code>IO::WaitWritable</code>. تقوم الوحدات (modules) بالابلاغ عن كيف ينبغي للمُستدعي (caller) الانتظار مع <code>IO.select</code>. في حال إطلاق <code>IO::WaitReadable</code> ، فسيكون على المُستدعي أن ينتظر لأجل القراءة. وفي حال إطلاق <code>IO::WaitWritable</code>، فيجب على المُستدعي أن ينتظر لأجل الكتابة.
ستُعاد القيمة <code>nil</code> إذا تم إعطاء قيمة للوسيط الاختياري <code>timeout</code>، ولم يكن هناك أي كائن <code>IO</code> جاهز خلال <code>timeout</code> ثانية.
لذلك، يمكن محاكاة حظر القراءة (<code>readpartial</code>) باستخدام <code>read_nonblock</code> و <code>IO.select</code> على النحو التالي:
 
تراقب <code>IO.select</code> المخزن المؤقت (buffer) لكائنات <code>IO</code> لاختبار قابليتها للقراءة. إذا لم يكن المخزن المؤقت <code>IO</code> فارغًا، فسيقوم التابع <code>IO.select</code> على الفور بالابلاغ عن جاهزية القراءة. هذه المراقبة لا تشمل إلا كائنات <code>IO</code>. ولا تحدث للكائنات شبيهة <code>IO</code> مثل<code>OpenSSL::SSL::SSLSocket</code>.
 
أفضل طريقة لاستخدام <code>IO.select</code> هي باستدعائها عقِب التوابع غير المُعطّلة (nonblocking methods)، مثل <code>read_nonblock</code> و <code>write_nonblock</code> ، وغيرهما. تطلق التوابع استثناء، والذي يُوسّع بواسطة <code>IO::WaitReadable</code> أو <code>IO::WaitWritable</code>. تقوم الوحدات (modules) بالابلاغ عن كيف ينبغي للمُستدعي (caller) الانتظار مع <code>IO.select</code>. في حال إطلاق <code>IO::WaitReadable</code> ، فسيكون على المُستدعي أن ينتظر لأجل القراءة. وفي حال إطلاق <code>IO::WaitWritable</code>، فيجب على المُستدعي أن ينتظر لأجل الكتابة.
 
لذلك، يمكن محاكاة حظر القراءة (<code>readpartial</code>) باستخدام <code>read_nonblock</code> و <code>IO.select</code> على النحو التالي:<syntaxhighlight lang="ruby">begin
  result = io_like.read_nonblock(maxlen)
rescue IO::WaitReadable
  IO.select([io_like])
  retry
rescue IO::WaitWritable
  IO.select(nil, [io_like])
  retry
end</syntaxhighlight>
عمومًا، يُفضل الجمع بين التوابع غير المُعطلة و <code>IO.select</code> بالنسبة للكائنات شبيهة <code>IO</code>، مثل <code>OpenSSL::SSL::SSLSocket</code>. إذ يعيد تابعها<code>to_io</code> الكائن <code>IO</code> الأساسي. كما يستدعي <code>IO.select</code> التابع <code>to_io</code> لأجل الحصول على واصف الملف (file descriptor) المُنتظر.


على نحو خاص، يُفضل الجمع بين التوابع غير المُعطلة و <code>IO.select</code> للكائنات من صنف <code>IO</code>، مثل <code>OpenSSL::SSL::SSLSocket</code>. لديها طريقة <code>to_io</code> لإرجاع الكائن <code>IO</code> الأساسي. يستدعي <code>IO.select</code> التابع <code>to_io</code> لأجل الحصول على واصف الملف (file descriptor) المُنتظر.
هذا يعني أن الإبلاغ عن قابلية القراءة من طرف <code>IO.select</code> لا تعني إمكانية القراءة من الكائن <code>OpenSSL::SSL::SSLSocket</code>.
هذا يعني أن الإبلاغ عن قابلية القراءة من طرف <code>IO.select</code> لا تعني إمكانية القراءة من الكائن <code>OpenSSL::SSL::SSLSocket</code>.
وعلى الأرجح أن <code>OpenSSL::SSL::SSLSocket</code> تخزّن مؤقتا بعض البيانات. لا يرى <code>IO.select</code> المخزن المؤقت. لذلك يمكن للتابع <code>IO.select</code> أن يُعطل عندما لا يفعل <code>OpenSSL::SSL::SSLSocket#readpartial</code>.
لكن توجد حالات أكثر تعقيدًا.
SSL هو بروتوكول، وهو عبارة عن تسلسل السجلات. تتكون السجلات من عدة بتات. لذا، يرسل الجانب البعيد من SSL سجلًا جزئيًا، يقوم <code>IO.select</code> بالابلاغ عن إمكانية القراءة، ولكن لا يمكن لـ <code>OpenSSL::SSL::SSLSocket</code> فك التشفير البايت، فيقوم <code>OpenSSL::SSL::SSLSocket#readpartial</code> بالتعطيل.
يمكن أيضًا للجانب البعيد أن يطلب إعادة التفاوض حول SSL، والذي سيُجبر محرك SSL المحلي على كتابة بعض البيانات. هذا يعني أنّ <code>OpenSSL::SSL::SSLSocket#readpartial</code> قد ينفذ نظام الاستدعاء <code>write</code> ويمكنه الحجب. في مثل هذه الحالة، يطلق <code>OpenSSL::SSL::SSLSocket#read_nonblock</code> الاستثناء <code>IO::WaitWritable</code> بدلاً من التعطيل. لذلك، سيكون على المتصل الانتظار إلى حين جاهزية الكتابة كما هو مذكور أعلاه.
الجمع بين التوابع غير المُعطلة و <code>IO.select</code> مفيد أيضًا للمجاري (streams) مثل tty ، والقنوات pipe socket عندما تقوم عدة عمليات بالقراءة من مجرى معيّن.
وأخيراً، لا يمكن لمطوري نواة لينكس (Linux kernel developers) أنّ قابلية القراءة select(2) تعني قابلية القراءة لـ read(2) حتى ولو في نفس العملية. انظر توثيق select(2) في نظام جنو / لينكس.
استدعاء <code>IO.select</code> قبل <code>IO#readpartial</code> يعمل بشكل جيد كالمعتاد. لكنه ليست الطريقة الأفضل لاستخدام <code>IO.select</code>.
لا تُظهر قابلية الكتابة المُبلغ عنها من طرف select (2) عن عدد البايتات القابلة للكتابة. يتجمّد التابع <code>IO#write</code> إلى أن حين كتابة السلسلة النصية المعطاة كاملة. لذلك ، يمكن أن يُعطل <code>IO#write(two or more bytes)</code> بعد الابلاغ عن قابلية الكتابة من قبل <code>IO.select</code>. لتجنب التعطيل، لا بد من <code>IO#write_nonblock</code>.
يمكن محاكاة تعطيل الكتابة (<code>write</code>) باستخدام <code>write_nonblock</code> و <code>IO.select</code> كما يلي: يجب أن يتم حفظ <code>IO::WaitReadable</code> لأجل إعادة التفاوض SSL في <code>OpenSSL::SSL::SSLSocket</code>.


Parameters<code></code> <code>↑</code>
على الأرجح أنّ <code>OpenSSL::SSL::SSLSocket</code> تخزّن مؤقتا بعض البيانات. لكن لا يرى <code>IO.select</code> المخزن المؤقت (buffer). لذلك يمكنه أن يُعطل (block) عندما لا يفعل <code>OpenSSL::SSL::SSLSocket#readpartial</code>. لكن توجد حالات أكثر تعقيدًا.
read_array مصفوفة من كائنات <code>IO</code> التي تنتظر إلى حين جاهزية القراءة. write_array مصفوفة من كائنات <code>IO</code>، والتي تنتظر حتى جاهزية الكتابة error_array مصفوفة من كائنات <code>IO</code> التي تنتظر الاستثناءات timeout قيمة عددية بالثواني
Example<code>¶</code> <code>↑</code>


الناتج:
SSL هو بروتوكول، وهو عبارة عن تسلسل للسجلات (sequence of records). تتكون السجلات من عدة بتات. لذا، يرسل الجانب البعيد من SSL سجلًا جزئيًا، يقوم <code>IO.select</code> بالابلاغ عن إمكانية القراءة، ولكن لا يمكن لـ <code>OpenSSL::SSL::SSLSocket</code> فك التشفير البايتات، فيقوم <code>OpenSSL::SSL::SSLSocket#readpartial</code> بالتعطيل.
 
يمكن أيضًا للجانب البعيد أن يطلب إعادة تفاوض أمني SSL، والذي سيُجبر محرك SSL المحلي على كتابة بعض البيانات. هذا يعني أنّ <code>OpenSSL::SSL::SSLSocket#readpartial</code> قد يستدعي نظام الاستدعاء <code>write</code> ويمكنه التعطيل في مثل هذه الحالة، يُطلق <code>OpenSSL::SSL::SSLSocket#read_nonblock</code> الاستثناء <code>IO::WaitWritable</code>، بدلاً من التعطيل. لذلك، سيكون على المتصل الانتظار إلى حين جاهزية الكتابة كما هو مذكور أعلاه.
 
الجمع بين التوابع غير المُعطلة و <code>IO.select</code> مفيد أيضًا للمجاري (streams) مثل <code>tty</code> ، والقنوات (pipe socket)، عندما تقوم عدة عمليات بالقراءة من مجرى معيّن.
 
وأخيراً، لا يمكن لمطوري نواة لينكس (Linux kernel developers) أن يكونوا على يقين بأنّ قابلية القراءة <code>select(2)‎</code> تعني قابلية القراءة لـ <code>read(2)</code>‎ حتى ولو في نفس العملية. انظر توثيق <code>select(2)</code> ‎ في نظام جنو / لينكس.
 
استدعاء <code>IO.select</code> قبل <code>IO#readpartial</code> يعمل بشكل جيد كالمعتاد. لكنه ليس الطريقة المثلى لاستخدام <code>IO.select</code>.
 
لا تُظهر قابلية الكتابة المُبلغ عنها من طرف <code>select (2)‎</code> عن عدد البايتات القابلة للكتابة. يتعطّل التابع <code>IO#write</code> إلى حين كتابة السلسلة النصية المعطاة كاملة. لذلك ، يمكن أن يُعطل <code>IO#write(two or more bytes)‎</code> بعد الابلاغ عن قابلية الكتابة من قبل <code>IO.select</code>. لتجنب التعطيل، لا بد من استخدام<code>IO#write_nonblock</code>.
 
يمكن محاكاة تعطيل الكتابة (<code>write</code>) باستخدام <code>write_nonblock</code> و <code>IO.select</code> كما يلي: يجب أن يتم حفظ <code>IO::WaitReadable</code> لأجل إعادة التفاوض الأمني SSL في <code>OpenSSL::SSL::SSLSocket</code>. <syntaxhighlight lang="ruby">while 0 < string.bytesize
  begin
    written = io_like.write_nonblock(string)
  rescue IO::WaitReadable
    IO.select([io_like])
    retry
  rescue IO::WaitWritable
    IO.select(nil, [io_like])
    retry
  end
  string = string.byteslice(written..-1)
end</syntaxhighlight>
==البنية العامة==
==البنية العامة==
<syntaxhighlight lang="ruby">select(read_array [, write_array [, error_array [, timeout]]]) → array or nil‎</syntaxhighlight>
<syntaxhighlight lang="ruby">select(read_array [, write_array [, error_array [, timeout]]]) → array or nil‎</syntaxhighlight>
==المعاملات==
==المعاملات==
===<code>read_array‎</code>===
===<code>read_array‎</code>===
مصفوفة من كائنات <code>IO</code> التي تنتظر إلى حين جاهزية القراءة.


===<code>write_array‎</code>===
===<code>write_array‎</code>===
مصفوفة من كائنات <code>IO</code>، والتي تنتظر حتى جاهزية الكتابة


===<code>error_array‎</code>===
===<code>error_array‎</code>===
مصفوفة من كائنات <code>IO</code> التي تنتظر الاستثناءات


===<code>timeout‎</code>===
===<code>timeout‎</code>===


 
قيمة عددية تمثل عدد ثواني الانتظار.
==القيمة المُعادة==
==القيمة المُعادة==
يعيد مصفوفة تحتوي على مصفوفات مكونة من كائنات <code>IO</code> السابقة.  ستُعاد القيمة <code>nil</code> إذا تم إعطاء قيمة للوسيط الاختياري <code>timeout</code>، ولم يكن هناك أي كائن <code>IO</code> جاهز خلال <code>timeout</code> ثانية.


==أمثلة==
==أمثلة==
مثال على استخدام التابع <code>select‎</code>:
مثال على استخدام التابع <code>select‎</code>:
<syntaxhighlight lang="ruby">begin
<syntaxhighlight lang="ruby">rp, wp = IO.pipe
  result = io_like.read_nonblock(maxlen)
mesg = "ping "
rescue IO::WaitReadable
100.times {
   IO.select([io_like])
  # IO.select follows IO#read.  Not the best way to use IO.select.
   retry
   rs, ws, = IO.select([rp], [wp])
rescue IO::WaitWritable
   if r = rs[0]
   IO.select(nil, [io_like])
    ret = r.read(5)
   retry
    print ret
end‎</syntaxhighlight>
    case ret
    when /ping/
      mesg = "pong\n"
    when /pong/
      mesg = "ping "
    end
  end
   if w = ws[0]
    w.write(mesg)
   end
}
</syntaxhighlight>الناتج:<syntaxhighlight lang="ruby">ping pong
ping pong
ping pong
(snipped)
ping
</syntaxhighlight>
==انظر أيضا==
==انظر أيضا==
* التابع <code>[[Ruby/Kernel/require_relative|require_relative]]</code>: عند استدعاء هذا التابع ستحاول روبي تحميل المكتبة المسماة في الوسيط المعطى string نسبة إلى مسار الملف المطلوب.  إذا تعذر تحديد مسار الملف، سيُطلق خطأ <code>LoadError</code>. إذا تم تحميل ملف ستُعاد القيمة <code>true</code>، وإلا فستُعاد false على خلاف ذلك.
* التابع <code>[[Ruby/Kernel/require_relative|require_relative]]</code>: عند استدعاء هذا التابع ستحاول روبي تحميل المكتبة المسماة في الوسيط المعطى string نسبة إلى مسار الملف المطلوب.  إذا تعذر تحديد مسار الملف، سيُطلق خطأ <code>LoadError</code>. إذا تم تحميل ملف ستُعاد القيمة <code>true</code>، وإلا فستُعاد false على خلاف ذلك.

مراجعة 16:06، 22 أكتوبر 2018

يستدعي هذا التابع نظام الاستدعاء select(2)‎. ويقوم بمراقبة (monitors) المصفوفات المعطاة المكونة من كائنات IO، وينتظر حتى يكون أحد كائنات IO جاهزًا للقراءة ، وللكتابة، ويكون لها استثناءات معلقة (pending exceptions) تواليًا، ثم يعيد مصفوفة تحتوي على مصفوفات مكونة من كائنات IO السابقة.

ستُعاد القيمة nil إذا تم إعطاء قيمة للوسيط الاختياري timeout، ولم يكن هناك أي كائن IO جاهز خلال timeout ثانية.

تراقب IO.select المخزن المؤقت (buffer) لكائنات IO لاختبار قابليتها للقراءة. إذا لم يكن المخزن المؤقت IO فارغًا، فسيقوم التابع IO.select على الفور بالابلاغ عن جاهزية القراءة. هذه المراقبة لا تشمل إلا كائنات IO. ولا تحدث للكائنات شبيهة IO مثلOpenSSL::SSL::SSLSocket.

أفضل طريقة لاستخدام IO.select هي باستدعائها عقِب التوابع غير المُعطّلة (nonblocking methods)، مثل read_nonblock و write_nonblock ، وغيرهما. تطلق التوابع استثناء، والذي يُوسّع بواسطة IO::WaitReadable أو IO::WaitWritable. تقوم الوحدات (modules) بالابلاغ عن كيف ينبغي للمُستدعي (caller) الانتظار مع IO.select. في حال إطلاق IO::WaitReadable ، فسيكون على المُستدعي أن ينتظر لأجل القراءة. وفي حال إطلاق IO::WaitWritable، فيجب على المُستدعي أن ينتظر لأجل الكتابة.

لذلك، يمكن محاكاة حظر القراءة (readpartial) باستخدام read_nonblock و IO.select على النحو التالي:

begin
  result = io_like.read_nonblock(maxlen)
rescue IO::WaitReadable
  IO.select([io_like])
  retry
rescue IO::WaitWritable
  IO.select(nil, [io_like])
  retry
end

عمومًا، يُفضل الجمع بين التوابع غير المُعطلة و IO.select بالنسبة للكائنات شبيهة IO، مثل OpenSSL::SSL::SSLSocket. إذ يعيد تابعهاto_io الكائن IO الأساسي. كما يستدعي IO.select التابع to_io لأجل الحصول على واصف الملف (file descriptor) المُنتظر.

هذا يعني أن الإبلاغ عن قابلية القراءة من طرف IO.select لا تعني إمكانية القراءة من الكائن OpenSSL::SSL::SSLSocket.

على الأرجح أنّ OpenSSL::SSL::SSLSocket تخزّن مؤقتا بعض البيانات. لكن لا يرى IO.select المخزن المؤقت (buffer). لذلك يمكنه أن يُعطل (block) عندما لا يفعل OpenSSL::SSL::SSLSocket#readpartial. لكن توجد حالات أكثر تعقيدًا.

SSL هو بروتوكول، وهو عبارة عن تسلسل للسجلات (sequence of records). تتكون السجلات من عدة بتات. لذا، يرسل الجانب البعيد من SSL سجلًا جزئيًا، يقوم IO.select بالابلاغ عن إمكانية القراءة، ولكن لا يمكن لـ OpenSSL::SSL::SSLSocket فك التشفير البايتات، فيقوم OpenSSL::SSL::SSLSocket#readpartial بالتعطيل.

يمكن أيضًا للجانب البعيد أن يطلب إعادة تفاوض أمني SSL، والذي سيُجبر محرك SSL المحلي على كتابة بعض البيانات. هذا يعني أنّ OpenSSL::SSL::SSLSocket#readpartial قد يستدعي نظام الاستدعاء write ويمكنه التعطيل في مثل هذه الحالة، يُطلق OpenSSL::SSL::SSLSocket#read_nonblock الاستثناء IO::WaitWritable، بدلاً من التعطيل. لذلك، سيكون على المتصل الانتظار إلى حين جاهزية الكتابة كما هو مذكور أعلاه.

الجمع بين التوابع غير المُعطلة و IO.select مفيد أيضًا للمجاري (streams) مثل tty ، والقنوات (pipe socket)، عندما تقوم عدة عمليات بالقراءة من مجرى معيّن.

وأخيراً، لا يمكن لمطوري نواة لينكس (Linux kernel developers) أن يكونوا على يقين بأنّ قابلية القراءة select(2)‎ تعني قابلية القراءة لـ read(2)‎ حتى ولو في نفس العملية. انظر توثيق select(2) ‎ في نظام جنو / لينكس.

استدعاء IO.select قبل IO#readpartial يعمل بشكل جيد كالمعتاد. لكنه ليس الطريقة المثلى لاستخدام IO.select.

لا تُظهر قابلية الكتابة المُبلغ عنها من طرف select (2)‎ عن عدد البايتات القابلة للكتابة. يتعطّل التابع IO#write إلى حين كتابة السلسلة النصية المعطاة كاملة. لذلك ، يمكن أن يُعطل IO#write(two or more bytes)‎ بعد الابلاغ عن قابلية الكتابة من قبل IO.select. لتجنب التعطيل، لا بد من استخدامIO#write_nonblock.

يمكن محاكاة تعطيل الكتابة (write) باستخدام write_nonblock و IO.select كما يلي: يجب أن يتم حفظ IO::WaitReadable لأجل إعادة التفاوض الأمني SSL في OpenSSL::SSL::SSLSocket.

while 0 < string.bytesize
  begin
    written = io_like.write_nonblock(string)
  rescue IO::WaitReadable
    IO.select([io_like])
    retry
  rescue IO::WaitWritable
    IO.select(nil, [io_like])
    retry
  end
  string = string.byteslice(written..-1)
end

البنية العامة

select(read_array [, write_array [, error_array [, timeout]]])  array or nil

المعاملات

read_array‎

مصفوفة من كائنات IO التي تنتظر إلى حين جاهزية القراءة.

write_array‎

مصفوفة من كائنات IO، والتي تنتظر حتى جاهزية الكتابة

error_array‎

مصفوفة من كائنات IO التي تنتظر الاستثناءات

timeout‎

قيمة عددية تمثل عدد ثواني الانتظار.

القيمة المُعادة

يعيد مصفوفة تحتوي على مصفوفات مكونة من كائنات IO السابقة. ستُعاد القيمة nil إذا تم إعطاء قيمة للوسيط الاختياري timeout، ولم يكن هناك أي كائن IO جاهز خلال timeout ثانية.

أمثلة

مثال على استخدام التابع select‎:

rp, wp = IO.pipe
mesg = "ping "
100.times {
  # IO.select follows IO#read.  Not the best way to use IO.select.
  rs, ws, = IO.select([rp], [wp])
  if r = rs[0]
    ret = r.read(5)
    print ret
    case ret
    when /ping/
      mesg = "pong\n"
    when /pong/
      mesg = "ping "
    end
  end
  if w = ws[0]
    w.write(mesg)
  end
}

الناتج:

ping pong
ping pong
ping pong
(snipped)
ping

انظر أيضا

  • التابع require_relative: عند استدعاء هذا التابع ستحاول روبي تحميل المكتبة المسماة في الوسيط المعطى string نسبة إلى مسار الملف المطلوب. إذا تعذر تحديد مسار الملف، سيُطلق خطأ LoadError. إذا تم تحميل ملف ستُعاد القيمة true، وإلا فستُعاد false على خلاف ذلك.
  • التابع set_trace_func: يجعل التابع set_trace_func الوسيط المعطى proc كمتعقب (handler for tracing)، أو يعطل التعقب إن كان الوسيط يساوي nil.

مصادر