- Rust מבטיח בטיחות זיכרון בעת קומפילציה באמצעות בעלות, שאילה ומשך חיים, מבלי להשתמש באיסוף זבל.
- מערכת הסוגים וכללי הכינוי מאפשרים מקביליות ללא מרוצי נתונים באמצעות מוטקסים, ערוצים ומצביעים חכמים.
- Cargo, crates.io ומערכת אקולוגית פעילה מפשטים את ניהול התלות, הקומפילציה, הבדיקות והפריסה.
- הבנת structs, enums, Option ו-Result היא המפתח לטיפול בשגיאות ולמידול נתונים בטוחים ביישומים בו-זמניים.
חלודה הפכה לאחת מאותן שפות ש כל מפתח מערכות שומע את זה שוב ושוב.זה מהיר כמו C ו-C++, אבל עם דגש כמעט אובססיבי על בטיחות זיכרון וביצוע מקביליות מוצלח. זה לא סתם שיווק ריק: העיצוב שלו סובב סביב המהדר שמזהה שגיאות בזמן הקומפילציה - שגיאות שבשפות אחרות רואים רק כשהמערכת כבר נמצאת בתהליך ייצור... או כשהיא קורסת.
אם אתה מעוניין להבין כיצד Rust משיגה זיכרון בטוח ללא איסוף אשפה ומקביליות ללא חשש מריצות נתוניםמדריך זה הוא בשבילכם. נסקור הכל, החל מיסודות השפה והמערכת האקולוגית שלה ועד למושגים מרכזיים כמו בעלות, שאילת מידע, טיפוסים מורכבים, כלים כמו Cargo, ואפילו נבחן טיפוסים אטומיים ונעילה מנקודת מבט נגישה יותר עבור אלו שחדשים בתחום המקביליות, והכל תוך התמקדות באבטחה וביצועים.
מדריך Rust: ביצועים, בטיחות זיכרון ומקביליות
ראסט היא שפת תכנות תכנות מטרה כללית ורב-פרדיגמה, מיועדת תכנות מערכות ברמה נמוכה וגם עבור פרויקטים ברמה גבוההמ מערכות הפעלהממנועי משחקים ודפדפנים ועד שירותי אינטרנט בעלי ביצועים גבוהים, מקורו במוזילה במטרה לשפר את אבטחת התוכנה, במיוחד ברכיבים רגישים כמו מנוע דפדפן.
המאפיין המגדיר שלו הוא ש מבטיח בטיחות זיכרון בזמן קומפילציה מבלי להשתמש באוסף זבל. במקום זאת, Rust משתמשת במערכת בעלות ובודק שאילה שעוקב אחר אורך החיים של כל ערך והפניות אליו. זה מונע בעיות קלאסיות כמו מצביעים תלויים, גלישות מאגר או דליפות זיכרון מבלי לדרוש ספירת הפניות אוטומטית או איסוף זבל.
יתר על כן, חלודה נועדה להקל על בו-זמניות בטוחהמודל הסוג והבעלות שלו מונעים מרוצי נתונים בין הלידים, לפחות כל עוד הם נשארים בקוד Rust בטוח. משמעות הדבר היא שמצבים מסוכנים רבים מזוהים בזמן הקומפילציה, לפני ששורה אחת מבוצעת.
מכל הסיבות הללו, חברות גדולות כמו דרופבוקס, מיקרוסופט, אמזון או Google הם אימצו את Rust בחלקים קריטיים של התשתית שלהם. ולא במקרה היא עומדת בראש סקרי Stack Overflow במשך שנים כאחת השפות "האהובות ביותר" על ידי מפתחים: היא משלבת ביצועים בסגנון ++C עם מערך כלים מודרני (Cargo, crates.io) וקהילה פעילה מאוד, מה שנקרא Rustaceans.
מושגים בסיסיים: שפת תכנות, סוגים וזיכרון
לפני שנעמיק בפרטים הספציפיים של אבטחת זיכרון ובמקביליות, כדאי להבהיר כמה מושגים כלליים המופיעים לאורך כל הזמן כשעובדים עם חלודה, במיוחד אם אתם מגיעים משפות אחרות או רק מתחילים לתכנת.
שפת תכנות היא, בסופו של דבר, קבוצה של כללים ומבנים המאפשרים לך לתאר אלגוריתמים ולהפוך אותן לתוכניות הרצה. Rust מבצע קומפילציה לקוד מכונה מקורי באמצעות המהדר שלה. rustcלכן, הביצועים שאתה מקבל בדרך כלל דומים ל-C ו-C++.
ניהול זיכרון הוא התהליך שבו תוכנית שומר ומשחרר בלוקים של זיכרון בזמן ההפעלהשגיאות בתחום זה הן לרוב קטלניות: דליפות זיכרון (אי שחרור זיכרון שאינו בשימוש), פגיעה בנתונים כתוצאה מכתיבה מחוץ לתחום, או שימוש בזיכרון לאחר ששוחרר. חלודה מטפלת בכך באמצעות מערכת טיפוסים חזקה מאוד וכללים פורמליים לבעלות, השאלה ומשך חיים.
חלודה כוללת גם מונחים כמו סוגים חכמים ומצביעיםטיפוס מתאר איזה סוג נתונים משתנה מאחסן (מספרים שלמים, מספרים צפים, מחרוזות, מבנים וכו') וכיצד ניתן לטפל בהם. מצביעים חכמים (לדוגמה, Box, Rc y Arc) הם מבנים אשר עוטפים כתובות זיכרון ומוסיפים לוגיקה נוספת לניהול משאבים בצורה בטוחה, כגון ספירת הפניות משותפות או העברת ערכים לערימה.
בתחום התחרות, מושגים כגון תנאי מרוץ, מוטקסים וערוצים הם הופכים להכרחיים: מצב מרוץ מתרחש כאשר מספר הליכים ניגשים ומשנים משאב משותף בו זמנית ללא תיאום נאות; mutex (הדרה הדדית) מבטיח שרק הליך אחד ייכנס לחלק הקריטי בכל פעם; וערוצים מאפשרים שליחת הודעות בין הליכים מבלי לשתף זיכרון ישירות.
למה ללמוד Rust: בטיחות זיכרון ומקביליות ללא פחד
חלודה זכתה לתהילה בזכות ההצעה שלה שלושה עמודי תווך בעלי ערך רב לתכנות מודרניביצועים, אבטחה וכלים עדכניים. בואו נראה מדוע נקודות אלו כה רלוונטיות.
לגבי ביצועים, חלודה מתקמפל ישירות לקבצים בינאריים מקוריים ללא צורך במכונה וירטואלית או במתורגמן. מודל האבסטרקציות בעלות אפס שואף להבטיח שהאבסטרקציות ברמה גבוהה לא יוסיפו תקורה בזמן ריצה. לכן הוא אידיאלי לפיתוח מערכות. משחק, רכיבי דפדפן או מיקרו-שירותים בעלי השהייה נמוכה.
אבטחת הזיכרון מבוססת על מערכת בעלות והלוואותאין כלי לאסוף זבל, אבל המהדר יודע בדיוק למי שייך כל משאב, מתי הוא כבר לא נחוץ ומתי ניתן לשחרר אותו. זה מונע דליפות, מצביעים תלויים ורבות מהשגיאות שהפכו באופן מסורתי את תכנות C ו-C++ למסוכן כל כך.
בתחום התחרות, ראסט רודף אחר מה שבדרך כלל נקרא "מקביליות ללא פחד"מערכת הטיפוסים עצמה מונעת משורשי נתונים להתקיים בקוד מאובטח. אם ברצונך לשתף נתונים הניתנים לשינוי בין הליכים, תצטרך להשתמש בפרימיטיבים מתאימים כגון Mutex, RwLock o Arc, והמהדר יבטיח כי כללי הכינוי והשינוי יישמרו.
חוויית הפיתוח משופרת בעזרת כלים מודרניים כגון מטעןהוא כולל מנהל חבילות משולב ותשתית בנייה, ומערכת אקולוגית רחבה של ספריות (crates) המכסות הכל, החל מרשתות אסינכרוניות (Tokyo) ועד מסגרות אינטרנט (Actix, Rocket, Axum). כל זה נתמך על ידי קהילה פתוחה, פורה וסבלנית למדי, במיוחד למתחילים.
התקנה וכלים חיוניים: rustup, rustc ו-Cargo
כדי לכתוב ולהריץ את התוכניות הראשונות שלך ב-Rust, הדרך הרגילה להתחיל היא על ידי התקנת ערכת הכלים הרשמית באמצעות חלודה (ראה את מבוא מלא לחלודה), מתקין ומנהל גרסאות פשוט שעובד על כל מערכות ההפעלה העיקריות.
עם חלודה ניתן להתקין, לעדכן ולעבור בין גרסאות שונות של Rust (יציבה, בטא, לילית) מבלי לגרום לשום דבר לקרות. פשוט גשו לדף הכלים הרשמי של Rust ופעל לפי השלבים עבור המערכת שלכם. לאחר ההתקנה, המהדר יהיה זמין. rustc, מנהל הפרויקט cargo ושלו rustup אצלך מסוף.
המהדר rustc זה מה שהופך את קוד המקור שלך לקבצים בינאריים או ספריות ניתנות להפעלה. למרות שניתן להפעיל אותו ישירות עם פקוד כמו rustc main.rsבפועל, כמעט תמיד תעבדו דרך Cargo, שמטפלת בקריאות אל rustc עם האפשרויות הנכונות.
הכלי המרכזי של תהליך העבודה הוא מטעןבעזרת מספר מצומצם של פקודות, ניתן ליצור פרויקטים חדשים, לנהל תלויות, לקמפל, להריץ, לבדוק ולפרסם חבילות ב-crates.io. כמה פקודות בסיסיות נפוצות הן: cargo new, cargo build, cargo run, cargo test y cargo check, שבודק את הקוד מבלי לייצר את קובץ ההפעלה הסופי, אידיאלי לגילוי שגיאות במהירות.
אם אתם רוצים להתעסק בלי להתקין כלום, גן שעשועים חלודה (המפעיל המקוון הרשמי) ופלטפורמות כמו Replit מאפשרות לך לכתוב ולהריץ קטעי קוד קטנים מהדפדפן, מושלם להתנסות בדוגמאות זיכרון וקוד מקביליות מבלי שתצטרך להגדיר את כל הסביבה.
התוכנית הראשונה שלך: שלום, חלודה, וזרימה בסיסית
הדרך הקלאסית להתחיל שיחה בכל שפה היא עם ה"שלום עולם" המפורסם. ב-Rust, קובץ main.rs לפחות יכול להכיל משהו פשוט כמו פונקציה main שמדפיס מחרוזת על המסך.
מילת המפתח fn מציין שאנו מגדירים פונקציה, ו main זוהי נקודת הכניסה של התוכנית. בלוק הקוד של הפונקציה נמצא בתוך הסוגריים המסתלסלים. כדי לכתוב לקונסולה, השתמש ב- מאקרו println!, אשר מקבלת ליטרל מחרוזת (או תבנית עם סימניות) ושולחת אותה לפלט סטנדרטי שמסתיים בתו שורה חדשה.
אם מבצעים קומפילציה ישירה עם rustc main.rs, תקבל קובץ בינארי שניתן להפעיל (לדוגמה, main o main.exe (בהתאם למערכת). כשתפעילו אותו, תראו את ההודעה בטרמינל. אבל הדרך האידיומטית לעבוד עם Rust היא לתת ל-Cargo להוביל את הפרויקט.
עם cargo new nombre_proyecto מבנה תיקיות נוצר אוטומטית באמצעות src/main.rs כבר מוכן עם "שלום עולם" וקובץ Cargo.toml אשר מכיל מטא-דאטה ותלויות עתידיות. משם, cargo run לקמפל ולהריץ את הקובץ הבינאריוהוא מבצע קומפילציה מחדש רק כאשר הוא מזהה שינויים.
דרך עבודה זו לא רק נוחה, אלא גם מאפשרת לך להתרגל לשימוש במערכת האקולוגית הסטנדרטית של Rust מההתחלה, וזה מאוד שימושי כשאתה מתחיל להוסיף crates עבור מקביליות, רשתות, בדיקות או כל דבר אחר שאתה צריך.
// אנו מצהירים על הפונקציה הראשית: נקודת כניסה לתוכנית fn main() { // אנו משתמשים במאקרו println! כדי להדפיס טקסט לקונסולה println!("שלום עולם!"); }
משתנים, יכולת שינוי וסוגי נתונים בסיסיים
ב-Rust, משתנים מוצהרים באמצעות מילת המפתח let, וכברירת מחדל בלתי ניתנים לשינויבמילים אחרות, ברגע שאתה מקצה להם ערך, אינך יכול לשנות אותו אלא אם כן אתה מצהיר במפורש שהוא ניתן לשינוי עם mut.
אי-שינוי כברירת מחדל מסייע במניעת שגיאות לוגיות עדינות, במיוחד בתוכניות בו-זמניות שבהן מספר הליכים עשויים לרצות לשנות את אותו ערך. אם צריך לשנות אותו, כותבים משהו כמו let mut contador = 0;משם ניתן להקצות מחדש ערכים חדשים ל contador.
חלודה מאפשרת גם את מה שנקרא הַצלָלָהניתן להכריז על משתנה חדש עם אותו שם באותו היקף, תוך הסתרת הקודם. זה לא אותו דבר כמו מוטציה, מכיוון שאתה יוצר ערך חדש (שיכול להיות אפילו מסוג שונה). לדוגמה, ניתן להמיר ממחרוזת למספר שלם באמצעות אותו שם, כל עוד מדובר בהכריזה חדשה עם let.
מערכת הטיפוסים של חלודה היא סטטית, מה שאומר ש הסוג של כל משתנה ידוע בעת הקומפילציהעם זאת, הסקת סוגים היא די חזקה: אם אתה כותב let x = 5;המהדר מניח שמדובר ב- i32 אלא אם כן תציין אחרת. ניתן להוסיף הערות כגון let x: i64 = 5; כשאתה רוצה להיות מפורש.
בין סוגי הסקלרים הזמינים נמצאים המספרים השלמים עם סימן ולא עם סימן (i8, u8, i32וכו'), הצפים (f32, f64), הבוליאנים (bool) ותווי יוניקוד (char). סוגים פשוטים אלה בדרך כלל זולים להעתקה ורבים מיישמים את התכונה Copyמה שאומר שכאשר מקצים אותם או מעבירים אותם לפונקציה, הם מועתקים במקום מועברים.
מחרוזות בחלודה: &str ו-String
טיפול בטקסט ב-Rust יכול להיות מעט מבלבל בהתחלה מכיוון שהוא מבחין בבירור בין "פרוסות" שרשרת ורשתות קנייניותשני החלקים המרכזיים הם &str y String.
Un &str הוא פרוסה של שרשרת בלתי ניתנת לשינויתצוגה של רצף בתים UTF-8 המאוחסן איפשהו. דוגמאות אופייניות כוללות ליטרלים כמו "Hola"אשר מהסוג &'static str (הם קיימים לכל אורך חיי התוכנית ומוטמעים בקובץ הבינארי.) פרוסות אינן בעלות על הנתונים; הן רק מצביעות עליהם.
String, לעומת זאת, הוא מחרוזת משלה, ניתנת לשינוי ומתארחת בערימהניתן לשנות את גודלו, לשרשר אותו, להעביר אותו בין פונקציות על ידי הזזת התכונה שלו וכו'. הוא משמש לעתים קרובות כאשר רוצים לבנות טקסט דינמי או לאחסן אותו לטווח ארוך בתוך מבנים.
בתרחישים רבים תעברו בין אחד לשני: לדוגמה, תיצרו String::from("hola") מתוך פרוסהאו שתשאלו &str על ידי String על ידי העברת הפניות לפונקציות שצריכות רק לקרוא.
הפרדה זו בין נתונים בבעלות ונתונים מושאלים היא המפתח לניהול זיכרון ומשתרעת על שאר השפה: אוספים, מבנים ו-enums עוקבים אחר אותם רעיונות של מי הבעלים ומי רק מסתכל.
פונקציות, זרימת בקרה והערות
פונקציות ב-Rust מוגדרות באמצעות fn ולאפשר לארגן את התוכנית ליחידות לוגיות רב פעמיות. כל פונקציה מציינת סוג הפרמטרים שלו וסוג ההחזרה שלו בעקבות חץ ->אם הוא לא מחזיר שום דבר משמעותי, ההנחה היא שמדובר בסוג יוניטרי. ().
פרט חשוב הוא שהביטוי האחרון בפונקציה (או בכל בלוק) ללא נקודה-פסיק נלקח כערך המוחזר הבלתי נמנע. ניתן להשתמש return להחזרות מוקדמותאבל בקוד אידיומטי, לעתים קרובות פשוט משאירים את הביטוי הסופי בלי. ;.
זרימת הבקרה מטופלת באמצעות הקלאסיקה if/elseלולאות loop, while y forברוסטה, if זהו ביטוי שמחזיר ערךכך שתוכלו להשתמש בו ישירות ב- letבתנאי שהענפים מחזירים את אותו הסוג. לולאות for הם בדרך כלל מבצעים איטרציות על פני טווחים או איטרטורים של אוספים והם האפשרות המומלצת במקום אינדקסים ידניים.
כדי לתעד את הקוד ולהקל על כל מי שיבוא אחריו (כולל אתכם בעוד חודש), תוכלו להשתמש הערות שורה עם // או לחסום עם /* ... */בנוסף, Rust מציע הערות תיעוד עם /// אשר הופכים למסמכים שנוצרו, למרות שזה מתאים יותר לפרויקטים גדולים.
בעלות, השאלה ותקופות חיים: יסודות אבטחת הזיכרון
כאן אנו מגיעים ללב מודל הזיכרון של ראסט: מערכת ה... בעלות, הלוואה ומשך חייםכללים אלה מבטיחים שההפניות תמיד תקפות ושהזיכרון משוחרר בבטחה ללא הצטברות של זבל.
הכללים הבסיסיים של בעלות פשוטים להצהרה, אם כי ייתכן שיהיה קשה להפנים אותם בהתחלה: לכל ערך יש בעלים יחיד.יכול להיות רק בעלים אחד בכל פעם; וכאשר הבעלים עוזב את התחום שלו, הערך נהרס והזיכרון שלו משתחרר. זה חל, למשל, על Stringעם השלמת הבלוק שבו הוא הוכרז, הוא מופעל אוטומטית drop מה שמפנה את זיכרון ה-heap.
כאשר מקצים ערך מתאים למשתנה אחר או מעבירים אותו כערך לפונקציה, המאפיין מוזז. משמעות הדבר היא ש המשתנה המקורי מפסיק להיות תקף לאחר המעברסמנטיקה זו של תנועה מונעת שחרורים כפולים, מכיוון שלעולם אין שני בעלים שמנסים לשחרר את אותו משאב.
כדי לאפשר לחלקים מרובים של התוכנית גישה לאותו ערך מבלי לשנות בעלות, Rust מציגה הפניות והשאלה. כשאתה שואל, אתה יוצר הפניה. &T (בלתי ניתן לשינוי) או &mut T (ניתן לשינוי) לערך מבלי להעביר בעלות. ההלוואה מוגבלת על פי כללי מאמת ההלוואות., אשר בודק שההפניות אינן שורדות את הנתונים שאליהם הן מצביעות ושגישות ניתנות לשינוי וגישות משותפות אינן מעורבבות בצורה מסוכנת.
ניתן לסכם את כללי ההלוואה כדלקמן: בכל זמן נתון, תוכל/י לקבל מספר רב של הפניות בלתי ניתנות לשינוי לערך, או הפניה אחת ניתנת לשינויאבל לא שניהם בו זמנית. זה מבטל תנאי מרוץ בזיכרון משותף: או שיש קוראים רבים, או שיש כותב מבודד; לעולם לא קוראים וכותבים בו זמנית על אותם נתונים באותו רגע.
סוגים מורכבים: structs, enums ו- smart pointers
חלודה מספקת מספר דרכים לקבץ נתונים קשורים למבנים עשירים יותר, החל מ- סטרוקטורותstruct מאפשר לך להגדיר סוג מותאם אישית עם שדות בעלי שם, לדוגמה משתמש עם דוא"ל, שם, סטטוס פעילות ומונה כניסה.
כדי ליצור מופע של struct, ממלאים את כל השדות שלו, וניתן לסמן את המשתנה המכיל אותו כמשתנה הניתן לשינוי כדי לשנות את ערכיו מאוחר יותר. יש גם את תחביר עדכון ה-struct, המאפשר לבנות מופע חדש על ידי שימוש חוזר בשדות מסוימים משדות קיימים. ..otro_struct.
ل סיכומים הם עמוד תווך חיוני נוסף: הם מאפשרים לך להגדיר סוג שיכול להיות אחד מכמה וריאנטים אפשריים, לכל אחד נתונים משלו או בלעדיהם. דוגמה קלאסית היא enum עבור כתובות IP, עם וריאנט אחד V4 אשר מאחסן ארבע אוקטטים ועוד אחת V6 שמאחסן מחרוזת עם סימון IPv6.
הספרייה הסטנדרטית של Rust כוללת שני enums חשובים מאוד: Option<T> y Result<T, E>הראשון מייצג את נוכחותו או היעדרו של ערך (משהו או כלום), ומשמש כדי להימנע ממצביעי null; השני מדמה פעולות שיכולות להחזיר תוצאה נכונה או שגיאה, הדורש שטיפול בשגיאות יהיה מפורש ומאובטח.
כדי לנהל זיכרון דינמי ולשתף נתונים, Rust פיתחה מצביעים חכמים כמו Box<T>, אשר מעביר ערך לערימה ושומר על בעלות ייחודית; Rc<T>, ספירת הפניות משותפת עבור סביבות בעלות הליך משנה יחיד; ו- Arc<T>, דומה ל Rc אך בטוח עבור מספר הלידים. שימוש נכון בהם הוא קריטי בעת שילוב זיכרון דינמי עם מקביליות.
מטען ומערכת האקולוגית של ארגזים
מטען הוא הדבק שמחזיק את המערכת האקולוגית של חלודה יחד: מנהל את הקומפילציה, התלויות ומחזור חיי הפרויקטלכל פרויקט יש קובץ Cargo.toml אשר משמש כמניפסט, המצהיר על השם, הגרסה, מהדורת השפה ותלויות חיצוניות.
מדור קובץ זה מאפשר לך לרשום ארגזים של צד שלישי עם הגרסאות שלהם. כאשר אתה מפעיל cargo build o cargo runCargo מוריד אוטומטית את הארגזים האלה מ-crates.io, מעבד אותם ומקשר אותם לפרויקט שלך. כל כך קל להוסיף, למשל, מחוללי מספרים אקראיים, מסגרות אינטרנט או ספריות קריפטוגרפיות.
בין הפקודות הנפוצות ביותר הן cargo new להתחיל פרויקטים בינאריים o cargo new --lib עבור ספריות; cargo build לקמפל במצב ניפוי שגיאות; cargo build --release כדי להשיג גרסה אופטימלית ומכוונת ייצור; ו cargo test כדי להריץ את סוללת הבדיקות.
cargo check ראוי לאזכור מיוחד: הוא קומפיל את הקוד לנקודת ביניים מבלי ליצור קובץ בינארי, מה שהופך אותו להיות מהיר מאוד בזיהוי שגיאות קומפילציהזה מושלם לאיטרציה מהירה בזמן שבודק ההלוואות מצביע על בעיות עם מאפיינים, הפניות ומשכי חיים.
הודות למערכת אקולוגית זו, מקובל לבנות את הפרויקטים שלכם כארגזים קטנים ומוגדרים היטב, לשתף קוד ביניהם ולהשתמש מחדש בפתרונות שנוצרו על ידי הקהילה. עבור מקביליות מתקדמת, לדוגמה, יהיו לכם ארגזים כמו Tokio לתכנות אסינכרוני או Crossbeam למבני נתונים מקביליים בעלי ביצועים גבוהים.
מקביליות ב-Rust: חוטים, מוטקסים, ערוצים ואטומיקה
מקביליות היא אחת הסיבות לכך ש-Rust מעוררת עניין כה רב: היא מאפשרת לך לנצל מעבדים מרובי ליבות. מבלי ליפול לשגיאות האופייניות של הליכים וזיכרון משותףאם זו הפעם הראשונה שאתם ניגשים לנושאים אלה, כדאי להבחין בין מספר מושגים.
בו-זמניות כרוכה בביצוע משימות מרובות החופפות בזמן, על ליבה אחת או על מספר ליבות. ב-Rust, ניתן ליצור הליכי מערכת לביצוע עבודה במקביל, והשפה מנחה אותך להבטיח ששיתוף הנתונים ביניהם בטוח. שגיאה קלאסית היא מצב מרוץ, שבו שני הליכי משנה ניגשים לנתונים ומשנים אותם בו זמנית, והתוצאה תלויה בסדר הביצוע - משהו שקשה מאוד לאתר באגים.
כדי לתאם גישה לנתונים משותפים, Rust מסתמך על פרימיטיבים כגון mutexאשר מבטיחים הדרה הדדית: רק חוט אחד יכול להיכנס לקטע הקריטי בכל פעם. בשילוב עם Arc<T> כדי לשתף בעלות בין נימים, ניתן לבנות מבני נתונים משותפים העומדים בכללי הבעלות וההשאלה.
צורה נפוצה נוספת של תקשורת בין-הליכית, המעודדת מאוד ב-Rust, היא העברת הודעות באמצעות ערוציםלערוץ יש צד שולח וצד מקבל; הליכים מעבירים דרכו הודעות (ערכים), מה שמפחית את השימוש בזיכרון משותף הניתן לשינוי ומפשט את ההיגיון לגבי מצב המערכת.
כאשר מתעמקים במקביליות ברמה נמוכה, מופיעים הדברים הבאים: סוגים אטומייםגישה למשתנים אטומיים מתבצעת באמצעות פעולות שאינן ניתנות לחלוקה מנקודת מבט של הליך משנה. זה מאפשר הטמעה של מונים משותפים, דגלי מצב, תורים ללא נעילה ועוד. שליטה במשתנים אטומיים דורשת הבנת מודלי זיכרון ופקודות גישה, ולכן מפתחים רבים מעדיפים להתחיל עם mutexs וערוצים לפני שהם מתעמקים בפרטים אלה.
צעדים ראשונים ומשאבים ללימוד מקביליות ואטומית
אם אתם נכנסים לזירה ללא ניסיון קודם, דרך הפעולה הנבונה ביותר היא לבנות בסיס איתן של מושגים כלליים לפני התמודדות עם כלים מתקדמים כמו הטיפוסים האטומיים של Rust. ספרים כמו "Programming Rust" מציעים מבוא הדרגתי, אך זה נורמלי שעבודות המתמקדות בטיפוסים אטומיים ובמנעולים ייראו צפופות בהתחלה.
לשם נוחות רבה יותר, מומלץ להכיר תחילה את שרשורים מסורתיים, הרחקה הדדית והעברת מסרים ב-Rust. שחקו עם דוגמאות של std::thread, std::sync::Mutex, std::sync::Arc וערוצים של std::sync::mpsc זה עוזר לך להבין כיצד המהדר מנחה אותך ואילו שגיאות הוא נמנע.
במקביל, מומלץ מאוד לעיין במשאבי מבוא בנושא מקביליות באופן כללי, גם אם הם אינם מתמקדים ב-Rust: הבנת מהם תנאי מרוץ, מה משמעות חסימה, מה מרמז על זיכרון משותף לעומת העברת מסרים, וכיצד משתמשים במנעולים. ברגע שהמושגים האלה הופכים טבעיים עבורך, פיזיקה אטומית מפסיקה להיות "קסם שחור". והם הופכים לסתם עוד כלי, רק כלי עדין מאוד.
כשתחזרו לטקסטים מתקדמים יותר על אטומיקה ומנעולים ב-Rust, יהיה הרבה יותר קל לעקוב אחר ההיגיון אם כבר תבינו איזו בעיה כל מבנה מנסה לפתור: החל ממונה פשוט בטוח-הליך ועד מבנים נטולי מנעולים שממזערים ניגוד עניינים.
בסופו של דבר, Rust מציעה גם כלים פרימיטיבים ברמה גבוהה וגם כלים ברמה נמוכה מאוד, והמפתח הוא תמיד לבחור את רמת ההפשטה הבטוחה ביותר שתפתור את הבעיה שלך, תוך שימוש בקוד אטומי. unsafe רק כאשר זה באמת מוסיף ערך ואתם מבינים את השלכותיו במלואן.
כל המערכת האקולוגית הזו של סוגים, בעלות, שאילה, ארגזים, כלים ופרימיטיבים של מקביליות משתלבת יחד כדי להציע שפה שבה ניתן לכתוב. תוכנה מהירה, חזקה וקלה לתחזוקהזה ממזער סוגים רבים של שגיאות שפקדו באופן היסטורי את תכנות המערכות. ככל שתתרגלו בפרויקטים קטנים, תרגילים כמו Rustlings ותיעוד רשמי, מושגים אלה יהפכו מכללים נוקשים לבעלי ברית שמזהירים אתכם לפני שהבעיה מגיעה למצב הייצור.
כותב נלהב על עולם הבתים והטכנולוגיה בכלל. אני אוהב לחלוק את הידע שלי באמצעות כתיבה, וזה מה שאעשה בבלוג הזה, אראה לכם את כל הדברים הכי מעניינים על גאדג'טים, תוכנה, חומרה, טרנדים טכנולוגיים ועוד. המטרה שלי היא לעזור לך לנווט בעולם הדיגיטלי בצורה פשוטה ומשעשעת.