select — המתנה לאירועים על קבוצת זרמים

מודול זה מספק פונקציות להמתנה יעילה עד שזרם אחד או יותר (streams – אובייקטים דמויי קובץ המממשים את פרוטוקול הזרם, כגון sockets, UART-ים ואובייקטי I/O אחרים) מוכן לקריאה או לכתיבה, במקום המתנה עמוסה (busy-waiting) או חסימה על אובייקט יחיד.

האובייקט poll הוא הממשק המומלץ: הוא מתאים לזרמים רבים ונקי מהקצאות כאשר משתמשים בו דרך poll.ipoll(). הפונקציה ברמת המודול select() היא ממשק תאימות פחות יעיל.

דוגמה לשימוש באובייקט poll

import select

poller = select.poll()
poller.register(uart, select.POLLIN)

while True:
    # Wait up to 1000 ms for the UART to have data.
    for obj, event in poller.poll(1000):
        if event & select.POLLIN:
            print(obj.read())

דוגמה לשימוש בפונקציה ברמת המודול select()

import select

# Wait up to 1 second for the socket to become readable.
rlist, wlist, xlist = select.select([sock], [], [], 1.0)
if rlist:
    data = sock.recv(100)

פונקציות

select.select(rlist: List, wlist: List, xlist: List, timeout: float | None = None) Tuple[List, List, List]

המתן עד שאחד או יותר מאובייקטי הזרם הנתונים מוכן, או עד שפג timeout.

  • rlist הוא רשימת אובייקטים לניטור לצורך מוכנות לקריאה.

  • wlist הוא רשימת אובייקטים לניטור לצורך מוכנות לכתיבה.

  • xlist הוא רשימת אובייקטים לניטור לצורך מצב שגיאה או ניתוק (hang-up).

  • timeout הוא הזמן המרבי להמתנה, בשניות (מתקבל float). אם הוא מושמט או None הקריאה חוסמת ללא הגבלת זמן; 0 מחזיר מיד (poll ללא חסימה).

מחזיר tuple בן 3 רשימות (rlist, wlist, xlist). כל רשימה מוחזרת היא תת-הקבוצה של רשימת הקלט המתאימה המכילה את האובייקטים שהפכו למוכנים לקריאה, מוכנים לכתיבה, או שאיתתו על שגיאה/ניתוק, בהתאמה. אם timeout חולף ושום דבר אינו מוכן, כל שלוש הרשימות ריקות.

פונקציה זו פחות יעילה מ-poll (היא בונה מחדש את קבוצת ה-poll הפנימית שלה בכל קריאה); השתמשו ב-poll במקום זאת היכן שאפשר.

קבועים

select.POLLIN: int

יש נתונים זמינים לקריאה מהזרם.

select.POLLOUT: int

הזרם יכול לקבל נתונים נוספים לכתיבה.

select.POLLERR: int

מצב שגיאה התרחש בזרם. זהו אירוע לא מבוקש: הוא מדווח על ידי poll.poll() / poll.ipoll() גם אם לא נתבקש ב-eventmask, ואין זה תקף להעבירו כ-eventmask של קלט.

select.POLLHUP: int

הזרם נותק (hung up / disconnected). זהו אירוע לא מבוקש: הוא מדווח על ידי poll.poll() / poll.ipoll() גם אם לא נתבקש ב-eventmask, ואין זה תקף להעבירו כ-eventmask של קלט.

מחלקות

class select.poll

צור אובייקט polling שמתחזק קבוצה של זרמים רשומים (או כל אובייקט שחושף את פרוטוקול הזרם) וממתין ביעילות עד שאחד או יותר מהם הופך לקריא, כתיב, או מאותת על מצב חריג.

זרמים מתווספים באמצעות register(), מוסרים באמצעות unregister(), וניתן לשנות את קבוצת האירועים לניטור באמצעות modify(). לאחר ההגדרה, קראו ל-poll() כדי לחסום עד שמשהו מוכן (או עד שחולף timeout), או ל-ipoll() עבור גרסה מבוססת-איטרטור נקייה מהקצאות.

register(obj: Any, eventmask: int = select.POLLIN | select.POLLOUT) None

רשום את stream obj עבור polling, תוך ניטור האירועים הנתונים על ידי eventmask (ה-OR הלוגי של):

  • select.POLLIN – נתונים זמינים לקריאה

  • select.POLLOUT – הזרם יכול לקבל נתונים נוספים לכתיבה

eventmask מוגדר כברירת מחדל ל-select.POLLIN | select.POLLOUT.

select.POLLHUP ו-select.POLLERR אינם תקפים ב-eventmask של קלט – הם אירועים לא מבוקשים שמדווחים על ידי poll() / ipoll() ללא קשר לשאלה אם התבקשו (זה תואם לסמנטיקה של POSIX).

מותר לקרוא למתודה זו יותר מפעם אחת עבור אותו obj: קריאה עוקבת מעדכנת את מסכת האירועים של obj, בהתנהגות הדומה ל-modify().

unregister(obj: Any) None

הסר את obj מקבוצת הזרמים הרשומים. אין זו שגיאה לבטל רישום של obj שאינו רשום כעת (לקריאה אין השפעה במקרה זה).

modify(obj: Any, eventmask: int) None

שנה את מסכת האירועים עבור obj שכבר רשום ל-eventmask. זורק OSError עם errno.ENOENT אם obj אינו רשום.

poll(timeout: int = -1, /) List[Tuple]

חסום עד שלפחות זרם רשום אחד הופך למוכן או מאותת על מצב חריג, ואז החזר את רשימת הזרמים שירו.

timeout הוא הזמן המרבי להמתנה במילישניות. אם הוא מושמט או -1 הקריאה חוסמת ללא הגבלת זמן; 0 מחזיר מיד (poll ללא חסימה).

מחזיר רשימה של tuple-ים (obj, event, ...), אחד עבור כל זרם שירה. obj הוא הזרם הרשום ו-event הוא ה-OR הביטי של הדגלים select.POLLIN / select.POLLOUT / select.POLLERR / select.POLLHUP שהתרחשו. כל tuple עשוי להכיל אלמנטים נוספים המוגדרים על ידי המימוש, לכן אל תניחו אורך של 2 בדיוק. אם timeout חולף ושום דבר אינו מוכן, מוחזרת רשימה ריקה.

select.POLLHUP ו-select.POLLERR עשויים להיות מוחזרים בכל עת (גם אם לא התבקשו) ויש לפעול לפיהם – בדרך כלל על ידי ביטול רישום וסגירה של הזרם המושפע – אחרת קריאות עוקבות ימשיכו להחזיר מיד עם דגלים אלה מוגדרים עבור אותו זרם.

מובטח שכל פונקציות ה-callback המתוזמנות הממתינות ירוצו לפני הכניסה ללולאת ה-polling.

הבדל מ-CPython

tuple-ים מוחזרים עשויים להכיל יותר מ-2 אלמנטים, כמתואר לעיל.

ipoll(timeout: int = -1, flags: int = 0, /) Iterator[Tuple]

כמו poll(), אך במקום לבנות רשימה הוא מחזיר איטרטור שמניב tuple (obj, event, ...) אחד בכל פעם. זה נמנע מהקצאה בכל קריאה, מה שחשוב עבור מתזמני I/O אסינכרוניים.

ה-tuple המונב נמצא בבעלות הנקרא (callee-owned): הוא משמש שוב (נדרס) באיטרציה הבאה, לכן יש לצרוך את תוכנו בתוך גוף הלולאה ואסור לשמור הפניות אליו.

ל-timeout יש אותה משמעות כמו עבור poll(). אם flags הוא 1, נעשה שימוש בהתנהגות חד-פעמית (one-shot): לזרם שאירועו ירה מנוקה אוטומטית מסכת האירועים שלו (שקול ל-poll.modify(obj, 0)), כך שלא ידווחו עבורו אירועים נוספים עד שמסכתו תוגדר שוב באמצעות modify().

מובטח שכל פונקציות ה-callback המתוזמנות הממתינות ירוצו לפני הכניסה ללולאת ה-polling.

הבדל מ-CPython

מתודה זו היא הרחבה של MicroPython.