קלט/פלט · מטפלי קובץ קבצים ספריות

select#

או להגדיר את מטפל הקובץ של פלט ברירת המחדל, או לקרוא ל־syscall select(2) לריבוב I/O. אותו שם, שתי משימות לא־קשורות - מובחנות לפי מספר הארגומנטים.

צורת הארגומנט הבודד (או צורת ללא ארגומנטים) עוסקת בלאן print, printf, say, ו־write שולחים את הפלט שלהם כאשר אין נקיבה במטפל קובץ. צורת ארבעת הארגומנטים היא עטיפה ישירה סביב ה־syscall select(2) של BSD להמתנה על קבוצות של file descriptors.

תקציר#

select FILEHANDLE              # set default output handle, return old
select                         # return current default output handle
select RBITS, WBITS, EBITS, TIMEOUT   # select(2) syscall

מה מקבלים בחזרה#

select FILEHANDLE מחזיר את מטפל הקובץ שנבחר קודם (כ־typeglob), כך שתבנית ה־save/restore המקובלת עובדת:

my $old = select $fh;
$| = 1;
select $old;

select (ללא ארגומנטים) מחזיר את מטפל הקובץ הנבחר כעת. בהתחלת התוכנית זהו STDOUT.

select RBITS, WBITS, EBITS, TIMEOUT מחזיר דברים שונים בהקשרים שונים:

  • בהקשר סקלרי: מספר מטפלי הקובץ המוכנים, או -1 בשגיאה כאשר $! מוגדר.

  • בהקשר רשימה: ($nfound, $timeleft) - אותו $nfound בתוספת הזמן הנותר מ־TIMEOUT. קרנלים רבים אינם מעדכנים את $timeleft; באותן מערכות הוא תמיד שווה ל־TIMEOUT של הקלט.

בפקיעת timeout $nfound הוא 0. שלושת מסכות הביט (RBITS, WBITS, EBITS) מתעדכנות במקום כדי לציין אילו descriptors מוכנים - יש להעביר עותקים אם רוצים לשמר את המסכות המקוריות.

מצב גלובלי שהוא נוגע בו#

צורת הארגומנט הבודד משנה פיסת מצב גלובלי אחת של המפרש: מטפל הקובץ של פלט הנבחר כעת. בעוד המטפל הזה נבחר, משתנים אלה מתייחסים אליו, לא ל־STDOUT:

  • $| - דגל autoflush

  • $, - מפריד שדות של פלט

  • $\ - מפריד רשומות של פלט

  • $#, $%, $=, $-, $~, $^ - משתנים קשורים ל־format

זוהי הסיבה ש־my $old = select($fh); $| = 1; select($old); עובד: $| הוא תכונה של המטפל הנבחר, לא סקלר גלובלי.

צורת ארבעת הארגומנטים אינה נוגעת במצב פר־מפרש. היא עשויה להשאיר את $! מוגדר בשגיאה.

דוגמאות#

להפעיל autoflush על מטפל מבלי להפריע לברירת המחדל:

my $old = select $fh; $| = 1; select $old;

להפנות מחדש את print באופן זמני ולשחזר ביציאת הבלוק:

{
    my $old = select $log_fh;
    print "entry: $msg\n";       # goes to $log_fh
    select $old;
}

לישון 250 מילישניות באמצעות צורת ארבעת הארגומנטים:

select undef, undef, undef, 0.25;

להמתין עד 5 שניות ל־STDIN להפוך לקריא:

my $rin = '';
vec($rin, fileno(STDIN), 1) = 1;
my $nfound = select my $rout = $rin, undef, undef, 5;
if ($nfound) {
    my $line = <STDIN>;
}

לבנות מסכת קריאה על מספר מטפלים:

sub fhbits {
    my $bits = '';
    vec($bits, fileno($_), 1) = 1 for @_;
    return $bits;
}
my $rin = fhbits(\*STDIN, $sock);
my ($nfound, $timeleft) =
    select my $rout = $rin, undef, undef, 10;

מקרי קצה#

  • חלופה בסגנון מתודה. $fh->autoflush(1) מגדיר את דגל ה־autoflush על $fh מבלי לשנות את מטפל ברירת המחדל. עדיף כאשר נדרש רק לעדכן תכונה אחת של מטפל אחד - אין מצב גלובלי מעורב.

  • Localization של typeglob נקייה יותר עבור הפניות מחדש מוגבלות־תחום. local *STDOUT = $fh קושר מחדש את STDOUT עצמו עבור התחום הדינמי; ב־die המקורי משוחזר אוטומטית. select אינו משחזר ב־die. השניים אינם שווי־ערך: עם select הוראת print STDOUT ... מפורשת עדיין מגיעה ל־STDOUT האמיתי; עם צורת local *STDOUT, גם print STDOUT ... הולך למטפל הקשור מחדש.

  • צורת מסכת ביט דורשת בתים, לא רשימה של מספרי fileno שלמים. מסכת ביט היא מחרוזת ביט ארוזה שנבנתה עם vec; העברת רשימה של מספרים שלמים או הפניה מייצרת בשקט תוצאות שגויות (או מסכה ריקה).

  • undef עבור מסכה משמעו ״לא להמתין על הקבוצה הזו.״ יש להעביר undef עבור מסכות שלא אכפת מהן. מחרוזת ריקה '' טכנית גם עובדת אך פחות מקובלת.

  • Timeouts שבריריים עובדים. TIMEOUT הוא float בשניות. 0.25 הוא 250 מילישניות; 0 חוזר מיד (תשאול).

  • TIMEOUT של undef משמעו לחסום ללא הגבלה עד שלפחות descriptor אחד מוכן או שאות מגיע.

  • מסכות משונות במקום. בהחזרה, כל מסכה מחזיקה רק את הביטים עבור descriptors שמוכנים. אם נדרשים המקוריים אחר כך, יש להעביר עותקים - המבנה my $rout = $rin בשורת הקריאה עושה בדיוק את זה.

  • אין לערבב I/O עם buffering עם צורת ארבעת הארגומנטים. select מדווח על מוכנות ברמת הקרנל; readline, read, ואופרטור היהלום <> קוראים דרך מאגרי PerlIO שעשויים כבר להחזיק נתונים שלא נקראו שהקרנל אינו יודע עליהם. יש להשתמש ב־sysread לנתונים ברגע ש־select אומר שהדסקריפטור מוכן.

  • מוכנות מזויפת על סוקטים. ב־Unixes מסוימים select(2) עשוי לדווח על סוקט כ־״מוכן לקריאה״ כאשר read עוקב עדיין יחסום. יש להגדיר O_NONBLOCK על הסוקט אם זה חשוב.

  • התנהגות restart-after-signal תלויה במערכת. אות (לדוגמה SIGALRM) עשוי לגרום ל־select לחזור מוקדם עם $! == EINTR, או שהקרנל עשוי להפעיל מחדש את הקריאה בשקיפות. קוד נייד בודק EINTR במפורש.

  • מספר הארגומנטים מבחין בין שתי הצורות. ארגומנט אחד (או אפס) היא צורת מטפל ברירת המחדל; ארבעה בדיוק היא צורת ה־syscall. ספירות אחרות הן שגיאת תחביר.

הבדלים מ־upstream#

תואם מלא ל־upstream Perl 5.42.

ראו גם#

  • print - קורא את המטפל הנבחר כאשר לא ניתן מטפל קובץ; select הוא הדרך לשנות איזה מטפל זה

  • printf - אותו כלל של מטפל ברירת המחדל כמו print

  • write - פלט מבוסס־format; משתני top-of-form ואורך־עמוד עוקבים אחר המטפל הנבחר, לא אחר STDOUT

  • fileno - ממפה מטפל קובץ למספר descriptor שלם שדרוש בעת בניית מסכה

  • vec - אורז מספרי descriptor לתוך מחרוזת הביט שצורת ארבעת הארגומנטים מצפה לה

  • sysread - הקריאה ללא buffering שמשתמשים בה אחרי ש־select ארבע־ארגומנטים אומר שדסקריפטור מוכן

  • IO::Select - עטיפת עצם על צורת ארבעת הארגומנטים שמסתירה את חשבון מסכות הביט