קריאה אסינכרונית משרת HTTP בGO
-
@nigun אמר בקריאה אסינכרונית משרת HTTP בGO:
האם כל פעם שאני יוצר סטרינג חדש (רגיל) הוא מצביע לכתובת חדשה, ואם משתמשים בunsafe אז הוא מצביע על המקורי
או שזה עובד אחרת?זה עובד אחרת, זה תלוי אם
סביבת ההרצההקומפיילר חוששת שהבייטים ישתנו, משום שלכל סטרינג יש חוזה (implicit contract) שהוא לא הולך להשתנות (immutable), וסביבת ההרצההקומפיילר דואגת לאכוף את זה. (אבל בשימוש ב-unsafe אתה אומר לסביבת ההרצהקומפיילר "אל תדאג, אני יודע מה אני עושה, אל תתערב לי")
(אפשר לבדוק את זה על ידי הדפסת תוכן אובייקט ה-string כמו כאן)
(או שאפשר לקרוא את קוד המקור שלסביבת ההרצההקומפיילר...)package main import ( "fmt" "reflect" "unsafe" ) func main() { b := []byte("ABC") s := *(*string)(unsafe.Pointer(&b)) // מצביע על הבייטים המקוריים s2 := s // עדיין מצביע על הבייטים המקוריים s3 := string(b) // מעתיק את הבייטים המקוריים ומצביע על המיקום של הבייטים החדשים s4 := s3 // לא מעתיק את הבייטים המקוריים כי סביבת ההרצה בטוח שהבייטים המקוריים לא ישתנו s5 := string(s4) // עדיין לא מעתיק וכנ"ל dumpStringAddr(s) dumpStringAddr(s2) dumpStringAddr(s3) dumpStringAddr(s4) dumpStringAddr(s5) } func dumpStringAddr(s string) { address := (*reflect.StringHeader)(unsafe.Pointer(&s)).Data fmt.Printf("%08x\n", address) }
-
@yossiz
מה הצורה הכי נוחה ליצור משתנה חדש אחרי שכבר המשתנה הקודם נשמר בunsafe
אני עשיתי המרה לביטים ואז המרה חזרה לסטרינג השאלה האם יש משהו יותר אלגנטי?app.Get("/:number", func(c *fiber.Ctx) { number := c.Path() str := []byte(number) go myfunc(string(str) )
-
@dovid אמר בקריאה אסינכרונית משרת HTTP בGO:
הרי אם הוא משרשר את זה, אז בהכרח נוצרת כתובת חדשה, לא
לכאורה לא. כי זה אותו מחרוזת, למה ליצור כתובת חדשה.
(https://play.golang.org/p/BuugrOW8xuy)כמו"כ אני ניסיתי את הדוגמה הראשונה של פייבר עם שרשור וזה היה בסדר גמור. זה לא אותו נידון?
ניסיתי עכשיו על ידי שינוי שורה 14 ל-
number := c.Params("number") + ""
והתוצאה לא בסדר. (או שאנחנו לא מבינים אחד את השני ומדברים על דברים שונים?)
-
למה ליצור חדש? כי אין לו בכלל מקום במיקום המקורי אולי. לא יודע. הנה בדוגמה שלך זה יוצר חדש כשהשרשור לא ריק.
בבדיקה שלי המחרוזת ששירשרתי לא היתה ריקה, ולכן זה עבד, ככה:package main import ( "fmt" "time" "github.com/gofiber/fiber" ) func main() { app := fiber.New() app.Get("/:number", func(c *fiber.Ctx) { number := c.Params("number") + " " go myfunc(number) c.Send(number) }) app.Listen(3000) } func myfunc(number string) { fmt.Printf("number is %s \n", number) time.Sleep(1 * time.Second) fmt.Printf("number is now %s \n", number) }
-
@yossiz
הם עכשיו הוציאו גירסה חדשה (למה הם התחילו מגירסה 1.0 ולא 0.1? זה כבר שאלה אחרת)
שבה הם הוסיפו את האפשרות שכל הסטרינגים יהיו Immutable
זה טוב, אבל נראה לי שהברירת מחדל צריך להיות הפוך ומי שרוצה יוכל להשתמש בunsafe
גם יהיה נחמד אם יהיה אפשרות לשלב את שני הסוגים באותו שרת
למשל שפשוט יחזירו bytes והלקוח ימיר את זה כרצונו.
(אני לא כותב את זה בשרשור בגיטהאב כי אני לא בטוח שמה שאני אומר זה נכון) -
@nigun לכאורה אני מסכים לטענותיך
(אני גם לא הולך לכתוב, א) ענין כזה שהוא לא טכני גרידא אלא ענין של טעם וניסיון וכו' אני לא מחזיק את עצמי כמייבין ב) אם זה היה נוגע אלי והייתי רואה פרוייקט חדש שהולך בכיוון לא טוב, לא הייתי משקיע בו יותר מדי, חכה עד שזה יהיה production ready או שימות מיתה טבעית) -
-
בלי להעליב, זה מוגחך להציע הצעות שיפור בתחום שאתם מעולם לא התמחתם בו בפלטפורמה אחרת.
גם אני גם אתם ממש חסרי ניסיון טוטלית בעניין, וכל שיפוט בגובה העיניים שלנו הוא טפשות.
הבאג ש@yossiz גילה (שאולי נותן תחושה של שותפות כל שהיא עם המפתחים הללו), למרות שהוא חמור, אני חושב הוא לא חריג בשלד של פרוייקט צעיר ששמים דגש מטורף על ביצועים ושוכחים מטבע הדברים כמה דברים. המפתחים האלה לא יותר כשרוניים או מומחים ממכם אבל הם בעלי ניסיון בפלטפורמות אחרות, זה הא' ב' של פרוייקט שבא להחליף את האחרים.
מה שאני מתכוון לומר שאם אתם רוצים להציע שיפורים, תשתמשו במערכת דומה חמש שנים כמו שצריך בפרודוקשיין, ואז לטיפים שלכם יהיה ערך. -
עם זאת, נראה לי שזה לגיטימי לגמרי להציע את דעתך בנושא אחרי הקדמת התנצלות שאתה לא מונסה וכו' אבל בכל זאת נראה לך שכך וכך יהיה יותר טוב וכו'
לדוגמה:I am a not a very experienced Go progammer, but I was wondering if it wouldn't be better to return `[]byte` to the user, and thus give the user the power to decide on a case by case basis if to copy the bytes into a new string or not.
אגב, עכשיו שאני כותב את הרעיון אני חושב שאולי לא יאהבו את הרעיון כי אז אין להם שליטה על הביצועים ולא יוכלו לדווח על ביצועים פי 15 מ-express... (ויש גם את הענין של תאימות עם ה-API של express)
-
@yossiz בטח לגיטימי.
אני לא מדבר על הכתיבה, אפשר לכתוב גם שטויות אפילו.
אני מדבר על המוטיבציה: ההוא אמינא שיש לנו כמה רעיונות שיפור. צריך לסבול ממה שקיים בסביבת ייצור במשך תקופה ורק אז מבינים למה עושים ומה, ואז יש מה לחשוב שיש משהו שיכול לעזור. -
@yossiz
נראה לי שפיספסתי משהו
אני מנסה להבין מה יקרה אם אני יעשה דף login עם פיבר.
שהלקוח שולח את השם משתמש וסיסמה שלו, והשרת בודק במסד נתונים האם זה תואם, ואם כן מעביר אותו לחשבון שלו.
מה יקרה אם אתה תכנס חלקיק שניה אחרי, האם אני ימצא את עצמי בחשבון שלך?
כי המשתנה usernaem ישתנה מynigun לyossiz? אבל כיוון שאני קיבלתי את התשובה true מהמסד נתונים אני ימשיך במורד הסקריפט ללא הפרעה, עם השם משתמש שלך?
אם כן אז מה הועילו בשרת המהיר שלהם שאמור להחזיק אפלי בקשות בו זמנית, אם השרת ישתבש לגמרי?
לכן חשבתי שיתנו אופציה להחזיר בייטים ואז המתכנת יחליט על כל משתנה, האם זה משתנה שצריך להיות Immutable או unsafe.
ועדיין זה יהיה שרת מהיר כי הרבה מהשמשתנים יכולים להיות unsafe. -
@nigun אמר בקריאה אסינכרונית משרת HTTP בGO:
מה יקרה אם אני יעשה דף login עם פיבר
בהרבה מקרים ה-handler לא יחזור עם תשובה עד שסיימת לעבד את הנתונים שקיבלת בבקשה, כל כמה שה-handler לא חזר, אתה יכול להיות בטוח שביטים לא השתנו מאחורי גבך.
לדוגמה במקרה שלך של דף לוגין, הרי לא תחזיר תשובה עד שבדקת את הנתונים מול ה-DB.
הבעיה מתחילה רק כאשר אתה עושה משהו מצורה אסינכרונית ומיד משיב תשובה מבלי לחכות לגמר הפעולה.
נמצינו למדים שיש עוד דרך לעקוף בעיה זו (עד שיהיה פתרון נורמלי), והיינו להשהות את ה-handler עד אשר ייגמרו כל הפעולות האסינכרוניות.
(נראה לי שלא צריך להשהות את התשובה, מספיק להשהות את ה-return של ה-handler. צריך לבדוק אם זה נכון)