עבודה עם REST ופייתון

Guy Yafe

New member
עבודה עם REST ופייתון

יש לי אפליקציה שכתובה בJAVA, ומדי פעם צריכה להריץ קוד פייתון.
העיבוד מורכב מאוד, אבל הקלט והפלט שלו מאוד פשוטים, והכי חשוב אין שום state.
לכן חשבתי להקים תהליך פייתוני ולשלוח אליו את המידע על REST (תקשורת רשת היא לא צוואר בקבוק כאן).

השאלה היא מה הFW הנכון לעבודה?
התחלנו לעבוד עם FLASK + RestPlus, והבעיה שנתקלנו בה היא שלא הצלחנו לעשות היררכיה של משאבים, ומסתבר שמה שטריויאלי בJAVA, בעייתי בפייתון.
היינו צריכים להגדיר את כל הכתובות של המשאבים באותו מודול, מה שיצר בלגן.
אין לי מושג אם זה כי עשינו משהו לא נכון, או שפשוט ככה FLASK עובד.
חשבנו על DJANGO.

מה שאני מנסה להבין, היא מה הFW הכי נח לבנות איתו ממשק REST פשוט:
שרת HTTP,
אופציה לבנות היררכיה של משאבים.
דוגמה:
משאב אחר יקרא algorithms והיה במודול algorithms.py. (שיענה על בקשות HTTP שייועדו לכתובת /algorithms)
מתחתיו יהיו משאבים algo-a וכן algo-b והם ישבו תחת המודולים algo-a.py וכן algo-b.py ויענו על בקשות HTTP לכתובות algorithms/algo-a או algorithms/algo-b.
(תחת FLASK היינו צריכים לשים את המחלקות ואת כל המשאבים באותו מודול)

הצעות?
 

BravoMan

Active member
הקמת שירותי REST אינו התחום שלי,

אבל מה שאתה מתאר נשמע לי די overkill עבור מה שאתה צריך בפועל.
FW שלם כדי להריץ מה שמסתכם בכמה פונקציות עם פלט וקלט קטנים יחסית?
&nbsp
במיוחד DJANGO, שלהבנתי הוא FW די גדול וכבד שנועד לעשות הרבה יותר מלתת שירותי rest.
&nbsp
אז קודם כל אני רוצה לשאול:
הם קוד Python ירוץ מקומית על אותה מכונה עם קוד Java, או שעכשיו או בעתיד רוצים להעמיד אותו על מכונה משלו, או אתם מתכננים איזו ארכיטקטורת קלסטר או כל דבר מסובך ומבוזר אחר?
&nbsp
כי על פניו, הדבר הכי פשוט לעשות במקרה שלך הוא להפעיל את התהליך הפייטוני ישירות מ-Java, עם פרמטרים, ולקרוא את מה שהוא מחזיר.
בלי http, בלי REST, ובטח בלי FW כבדים ומסובכים.
פשוט קריאה מ-Java ל-Python.
 

Guy Yafe

New member
לא בדיוק overkill

הרמה של תהליך פייתוני מתוך JAVA נמשכת בערך שנייה, והחישוב נמשך 20ms, ודווקא זה overkill.
אנחנו מבצעים הרבה מאוד חישובים כאלה בשנייה (כרגע JAVA זה המנוע העיקרי, אבל חלק מהאלגוריתמיקה עדיין ממומשת בפייתון), ולכן אנחנו מעדיפים שהפייתון יהיה כל הזמן למעלה וימתין למידע.
אגב, לא מדובר בכמה פונקציות. כרגע יש לנו בערך 30 פונקציות שונות שצריך לגשת אליהן אליהן ולכן נדרש API מסודר.
&nbsp
DJANGO הוא אכן כבד בטירוף, ולכן בהתחלה ניסינו להימנע ממנו והלכנו על FLASK, אבל נראה שFLASK קצת פשטני מדי ולא מאפשר לנו היררכיה של משאבים.
 

selalerer

New member
אם ביצועים זה מה שחשוב לכם, למה להתעסק ב-http?

אם מדובר תקשור עם process מקומי, תשתמשו ב-pipe או shared memory.
&nbsp
אם רוצים גם בין מכונות, תשתמש ב-socket udp ולוגיקה של resend בעצמכם.
&nbsp
כיתבו פרוטוקל פשוט שנותן לכם את כל הפעולות שאתם צריכים (בקשות ותשובות) שדורש ממכם מינימום עבודה serialize ו-deserialze. לא לשכוח להכניס בתחילת כל הודעה מספר גרסה, בכדי שתוכלו לעדכן את הפרוטוקול בקלות בעתיד.
 

Guy Yafe

New member
דווקא זה overkill

משך החישוב הוא כ-200ms. הרמה של תהליך פייתון לוקחת שנייה עד שנייה וחצי, מה שהופך אותו לצוואר בקבוק.
בקשת HTTP נמשכת מילישניה וזה זניח מבחינתי.
כל התהליכים נמצאים על אותו שרת.
&nbsp
אם אני אצטרך עכשיו להקים תשתית חדשה, להגדיר פרוטוקול חדש ולהעביר את הכל אליו, מבחינתי זו תהיה השקעה מיותרת של ימי עבודה עבור חיסכון של עוד חצי מילישניה.
&nbsp
בנוסף, גם ככה, אני בקושי מצליח לשכנע את האלגריתמאים לעבוד בשיטה הזו, אז לשכנע אותם לעבוד עם מילים גסות כמו פרוטוקול או זיכרון משותף תהיה קרב אבוד מראש.
&nbsp
 

Guy Yafe

New member
שגיאת הדפסה

בכל מקרה מילישניה אחת על 20 מילישניות זה גם זניח מבחינתי
 

פרסאוס

New member
לא ממש כתבת איפה כשלתם, כך שקצת קשה לענות

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

Guy Yafe

New member
אנסה להרחיב

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

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

מבדיקות שעשינו, החישוב הפייתוני נמשך כ200 מילישניות, מה שאומר שהרמה של תהליך פייתוני (כשניה אחת) הוא צוואר בקבוק, אבל קריאה דרך הרשת (מילישניה אחת) אינה צוואר בקבוק.

אתאר דוגמה ל-API (באנגלית, יכול להיות שיש לי טעויות תחביריות בJSON):
קוד:
GET /algorithms - Returns  a list of available algorithms: ["/algorithms/distance", "/algorithms/DFS"]
POST /algorithms/distance with two points (e.g. [{"x":10,"y":10},{"x":20,"y":20}]) returns the distance between the points
כמובן שמדובר בהרבה יותר אלגוריתמים, ובהרבה יותר קריאות לפייתון שאינן אלגוריתמיקה וכל אלגוריתם מתחלק לתתי אלגוריתם וכו'.
השאלה שנשאלת היא איך לכתוב נכון את המשאבים (resources) בפייתון.

בJAVA זה מאוד קל (לדוגמה עם JAX-RS):
אני איצר מחלקה אחת בשם AlgorithmsResource. למחלקה הזו אצור מתודת getAlgorithms ואתן לה אנוטציה GET @
לאחר מכן אוסיף מתודה singleAlgorithm עם אנוטציה Path("{algorithmName}") zz @
המתודה הזו תחזיר מחלקה חדשה שנקראת SingleAlgorithm שתקרא שם האלגוריתם ותעביר אותו הלאה.

ההיררכיה הזו המחלקות שבהתאם לURI יודעת לאיזו מחלקה להעביר את הקריאה היא הדבר החשוב ואני לא מצליח להבין איך עושים אותה בפייתון.
כדי ליצור היררכיה במשאבים עם FLASK האופציה היחידה שלי היא להכניס את כל המחלקות לאותו מודול:
http://michal.karzynski.pl/blog/201...l-apis-using-flask-swagger-ui-flask-restplus/
הבלוג הנ"ל לדוגמה מראה שצריך ליצור קובץ אחד ולהגדיר בו את כל המסלולים.
השאלה היא איך אני יכול לפצל את המסלולים ואת תתי המסלולים לקבצים שונים אוטונומיים.
 

פרסאוס

New member
לא התעסקתי עם פלאסק

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

Guy Yafe

New member
השאלה איך עושים את זה

בבלוג שהראיתי, הם מראים דוגמה שבה שמים הכל בקובץ אחד.
אני לא אופתע אם בספריות הפשוטות זה לא אפשרי (RETROFIT ב - JAVA לדוגמה גם לא מאפשר את זה).
&nbsp
יכול שעדיף לעבור לעבוד עם - DJANGO?
 

פרסאוס

New member
לא יכול לומר בפסקנות

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