כיצד להשתמש ב- asyncio בפייתון

פונקציונליות התכנות האסינכרונית של פייתון, או בקיצור אסינכרון, מאפשרת לך לכתוב תוכניות שמבצעות עבודה רבה יותר על ידי כך שלא מחכים לסיום משימות עצמאיות. asyncioהספרייה המצורף Python נותן לך את הכלים לשימוש async לעיבוד לי דיסק או רשת / O בלי לחכות כל דבר אחר.

asyncio מספק שני סוגים של ממשקי API להתמודדות עם פעולות אסינכרוני:  ברמה גבוהה  ו  -רמה נמוכה . ממשקי ה- API ברמה גבוהה הם השימושיים בדרך כלל, והם ישימים למגוון הרחב ביותר של יישומים. ממשקי ה- API ברמה נמוכה הם רבי עוצמה, אך גם מורכבים ומשמשים בתדירות נמוכה יותר.

אנו נתרכז בממשקי ה- API ברמה הגבוהה במאמר זה. בחלקים שלהלן נעבור דרך ממשקי ה- API ברמה הגבוהה הנפוצה ביותר  asyncioונראה כיצד ניתן להשתמש בהם לצורך פעולות נפוצות הכוללות משימות אסינכרוניות. 

אם אתה חדש לגמרי באסינכרון ב- Python, או שאתה יכול להשתמש ברענון על אופן הפעולה שלך, קרא את ההקדמה שלי ל- Python async לפני שאתה צולל כאן.

הפעל קורוטינים ומשימות בפייתון

באופן טבעי, השימוש הנפוץ ביותר asyncioהוא הפעלת החלקים הא-סינכרוניים של סקריפט ה- Python שלך. פירוש הדבר ללמוד לעבוד עם קורוטינים ומשימות. 

ניתן להשתמש ברכיבי האסינכרון של Python, כולל קורוטינים ומשימות, רק עם רכיבי async אחרים, ולא עם Python סינכרוני קונבנציונאלי, לכן עליך  asyncio לגשר על הפער. לשם כך, אתה משתמש  asyncio.run בפונקציה:

ייבוא ​​asyncio

async def ראשי ():

הדפס ("מחכה 5 שניות.")

עבור _ בטווח (5):

לחכות asyncio.sleep (1)

הדפס (".")

הדפס ("סיים להמתין.")

asyncio.run (main ())

זה פועל main(), יחד עם כל קורוטינים יופעל  ,  main() ומחכה לתוצאה שתחזור.

ככלל, תוכנית פייתון צריכה לכלול .run() הצהרה אחת בלבד  , כמו שלתוכנית פייתון צריכה להיות main() פונקציה אחת בלבד  . Async, אם נעשה בו שימוש ברשלנות, יכול להקשות על זרימת הבקרה של התוכנית. לאחר נקודת כניסה יחידה לקוד האינק-סינכרון של התוכנית, מונעים מהדברים להיות שעירים.

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

async def my_task ():

עשה משהו()

משימה = asyncio.create_task (my_task ())

my_task() לאחר מכן מופעל בלולאת האירועים, כאשר התוצאות שלה מאוחסנות  task.

אם יש לך רק משימה אחת ממנה אתה רוצה להשיג תוצאות, אתה יכול להשתמש בה  asyncio.wait_for(task) כדי לחכות לסיום המשימה, ואז להשתמש  task.result() כדי לאחזר את התוצאה שלה. אך אם קבעתם מספר משימות לביצוע ותרצו להמתין   לסיום של כולן , השתמשו  asyncio.wait([task1, task2]) בכדי לאסוף את התוצאות. (שים לב שאתה יכול להגדיר פסק זמן לפעולות אם אתה לא רוצה שיעברו פרק זמן מסוים.)

נהל לולאת אירועים אסינקרית בפייתון

שימוש נפוץ נוסף עבור  asyncio הוא ניהול לולאת האירוע async  . לולאת האירוע היא אובייקט שמריץ פונקציות אסינכרון וקריאות חוזרות; זה נוצר באופן אוטומטי בעת השימוש  asyncio.run(). בדרך כלל אתה רוצה להשתמש בלולאת אירוע אסינכרונית אחת בלבד לכל תוכנית, שוב כדי לשמור על הניהול של הדברים.

אם אתה כותב תוכנה מתקדמת יותר, כגון שרת, תצטרך גישה ברמה נמוכה יותר ללולאת האירועים. לשם כך תוכלו "להרים את מכסה המנוע" ולעבוד ישירות עם הפנימיות של לולאת האירוע. אבל עבור עבודות פשוטות לא תצטרך.

קרא וכתוב נתונים עם זרמים בפייתון

התרחישים הטובים ביותר עבור async הם פעולות רשת ארוכות טווח, כאשר היישום עשוי לחסום המתנה למשאב אחר שיחזיר תוצאה. לשם כך  asyncio מציעים זרמים שהם מנגנונים ברמה גבוהה לביצוע קלט / פלט של רשת. זה כולל לפעול כשרת לבקשות רשת.

asyncio משתמשת בשתי כיתות,  StreamReader ו  StreamWriter, קרוא וכתוב מהרשת ברמה גבוהה. אם ברצונך לקרוא מהרשת, השתמש  asyncio.open_connection() בפתיחת החיבור. פונקציה זו מחזירה tuple של  StreamReader ו  StreamWriter אובייקטים, ואתה תשתמש  .read() ואת  .write() שיטות בכל לתקשר.

כדי לקבל חיבורים ממארחים מרוחקים, השתמש  asyncio.start_server(). asyncio.start_server()הפונקציה לוקחת כטיעון פונקציית callback,  client_connected_cbאשר נקראה בכול פעם שהוא מקבל בקשה. פונקציית callback זה לוקחת מקרים של  StreamReader ו StreamWriter כטיעונים, כך שתוכל להתמודד עם היגיון קריאה / כתיבה עבור השרת. (ראה כאן דוגמה לשרת HTTP פשוט המשתמש   בספריית asyncio-driven  aiohttp.)

סנכרן משימות בפייתון

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

  • תוריםasyncio תורים מאפשרים לפונקציות אסינכרוניות להרכיב אובייקטים של פייתון על ידי פונקציות אסינכרון אחרות - למשל, להפיץ עומסי עבודה בין סוגים שונים של פונקציות על סמך התנהגויותיהם.
  • פרימיטיבי סנכרון : מנעולים, אירועים, תנאים וסמפורות asyncioבעבודה כמו עמיתיהם המקובלים של פיתון. 

דבר אחד שיש לזכור בכל השיטות הללו הוא שהן  אינן בטיחות  חוטים. זה לא נושא למשימות אסינכרון הפועלות באותה לולאת אירועים. אך אם אתה מנסה לשתף מידע עם משימות בלולאת אירועים, שרשור מערכת הפעלה או תהליך אחר, תצטרך להשתמש  threading במודול ובאובייקטים שלו כדי לעשות זאת.

יתר על כן, אם ברצונכם  להפעיל  קורוטינים מעבר לגבולות השרשור, השתמשו  asyncio.run_coroutine_threadsafe() בפונקציה והעבירו את לולאת האירוע לשימוש איתה כפרמטר.

השהה קורוטין בפייתון

שימוש נפוץ נוסף  asyncio, ושימוש שלא נדון בו, מחכה למשך זמן שרירותי בתוך קוריאה. אינך יכול להשתמש  time.sleep() בזה או לחסום את התוכנית כולה. במקום זאת, השתמש  asyncio.sleep(), שמאפשר להמשיך בפעילות קורוטית אחרת.

השתמש באסינכרון ברמה נמוכה יותר בפייתון

לבסוף, אם אתה חושב שהאפליקציה שאתה בונה עשויה לדרוש asyncioרכיבים ברמה נמוכה יותר, התבונן סביב לפני שתתחיל בקידוד: יש סיכוי טוב שמישהו כבר בנה ספריית פייתון המופעלת על-ידי סינכרון שעושה את מה שאתה צריך.

לדוגמה, אם אתה זקוק לשאילתת DNS async, בדוק  aiodns בספרייה ולפגישות SSH של async, יש  asyncSSH. חפש ב- PyPI לפי מילת המפתח "async" (בתוספת מילות מפתח אחרות הקשורות למשימות), או בדוק ברשימת הרעיונות המדהימים של Asyncio המצויים ביד.