הפעם נדבר קצת על טרדים (Thread, נראה לי שקוראים לזה תהליכון בעברית, אבל אל תסמכו עלי בזה...)
יש כמה דברים בתיכנות שידע מעמיק הוא ממש חובה, אם יש כמה מחלקות שאני לא מכיר זאת לא בעיה בדרך כלל, חיפוש קטן בגוגל והכל בסדר, אבל אפליקציית MultiThreading לא כל כך לבנות, וכל פרט קטן עלול לשבש את כל האפליקציה, עדיף להשקיע קצת בהבנה ואולי יום אחד זה יועיל הרבה
אחד מהדברים שיכולים לשנות אפליקציה מקצה לקצה... אומנם הם בדרך כלל שימושיים באפליקציות שולחניות , אך גם בווב עשיתי בהם שימוש מדי פעם.
מה זה Thread? זה בעצם תהליך נוסף, מקביל, בתוכנית שלנו. בדרך כלל התוכנית רצה שורה שורה, מסיימת אחת ממשיכה לבאה, אבל מה קורה אם שורה זו פעולה ארוכה מאוד, ואני רוצה לשעשע את המשתמש בינתיים...? מה קורה אם בתוכנית יש הרבה פניות לאינטרנט, והסיבה שזה לוקח זמן זה לא בגלל שהמעבד עסוק אלא פשוט לשרת בצד השני של העולם לוקח זמן להגיב? למה לא לעשות דברים אחרים בינתיים? בשביל זה המציאו Threadים נוספים...
בואו נראה דוגמה קטנה
static void Main(string[] args)
{
Console.WriteLine("please wait...");
Thread t = new Thread(new ThreadStart(DoSomethingLong));
t.Start();
while (t.ThreadState != System.Threading.ThreadState.Stopped && t.ThreadState!= ThreadState.Aborted)
{
Console.WriteLine("still waiting..."+DateTime.Now);
Thread.Sleep(500);
}
Console.WriteLine("finished!");
}
private static void DoSomethingLong()
{
Thread.Sleep(5000);
}
אז מה יש לנו כאן... קודם כל אנו רואים שיש פונקציה שלוקח לה זמן לרוץ DoSomethingLong. בפונקציה הראשית אני יוצר אובייקט מסוג Thread, בקונסטרוקטור שלו אני מעביר את שם הפונקציה שאני רוצה שתרוץ. עד כאן שום דבר לא קרה, אך בשורה הבאה אנו נותנים לאובייקט פקודה לרוץ, ובאותו רגע נוצר בעצם תהליך חדש בתוכנית שלנו, שלא עוצר את התהליך הראשי- עובדה שאנו ממשיכים לשורה הבאה ומציגים למשתמש כל חצי שניה הודעה שעדיין אנו ממתינים שהפונקציה תסתיים, אם היינו עושים את זה ללא Thread נוסף אז לא היינו ממשיכים הלאה עד שהפונקציה היתה מסתיימת. השתמשתי בשיטה מסורבלת ולא נכונה כדי לבדוק מה מצב ה Thread הנוסף שלי- בדקתי אם הוא כבר עצר או נעצר כדי להחליט שהוא כבר סיים, אך יש שיטות יותר נכונות ויעילות שנראה תיכף.
*השתמשתי כאן בפונקציה הסטטית Thread.Sleep(5000) שגורמת לעצירה של התהליך הנוכחי למספר אלפיות השניה שאנו מעבירים לה.
בואו נתקן מעט את הפונקציה. לאחר הרצת ה Thread הנוסף, אני אמשיך לעשות מה שאני רוצה, ובסוף הפעולות שלי אני אמתין ל Thread הנוסף עד שיסתיים מבלי לרוץ בלולאה ומבלי לבדוק באופן ספציפי באיזה מצב הוא נמצא:
t.Join();
הפקודה בעצם עוצרת את Thread המרכזי שלנו, וממתינה ש t יסיים את כל מה שהוא צריך לעשות ורק אז נעבור לשורה הבאה
אם ארצה בכוח לעצור את ה Thread הנוסף ניתן להשתמש ב
t.Abort();
רק אזהרה קטנה - אל תעשו את זה!! אלא אם כן אתם חייבים לסיים בדחיפות את התוכנית ומוכנים לקחת את הסיכון...
הדבר עשוי לגרום ל"תוצאות בלתי צפויות" ולהשחתה של נתונים... בכל מקרה תשימו גם try catch מסביב לפקודה הזאת. יש דרכים יותר טובות להודיע לו שצריך לסיים בקרוב...
הדרך הטובה היא להשתמש במשתנה בוליאני, שאותה יבדוק ה Thread הנוסף שלנו לפני כל פעולה ארוכה או לופ שהוא הולך לבצע, ואם השתנה הערך, הוא פשוט יפסיק הכל ויחזור, וכך מהתוכנית הראשית שלנו, ברגע שנרצה לעצור את כל ה Threadים , נשנה להם את הערך של המשתנה הזה והם יבינו שצריך לעצור
שימו לב שניתן ליצור מחלקה חדשה, לתת לה נתונים ואז להריץ פונקציה ממנה בעזרת Thread אחר, וזה מה שנעשה עכשיו - נבנה מחלקה שמתחברת לאינטרנט, מורידה קובץ ושומרת אותו אצלנו במחשב. התוכנית הראשית תייצר אובייקטים מהמחלקה הזאת ,תיתן לכל אחת את הכותבת ממנה להוריד את הקובץ שלה, ותריץ אותה ב Thread נפרד
static void Main(string[] args)
{
string[] files ={
class="code_text">"http://www.someurl.com/myfile.pdf", "http://www.another.com/file.pdf","http://www.moreurl.com/morefiles.pdf"};
List<Thread> threads = new List<Thread>();
foreach (string url in files)
{
WebConnector wc = new WebConnector(url);
Thread t = new Thread(new ThreadStart(wc.Connect));//select the method to run
threads.Add(t);
t.Start();
}
foreach (Thread t in threads)
{
t.Join();
}
}
וזאת המחלקה שלנו שמבצעת את העבודה בפועל:
public class WebConnector
{
private string _url;
public WebConnector(string url)
{
this._url = url;
}
public void Connect()
{
try
{
WebClient wc = new WebClient();
string localFileName = Path.Combine(Directory.GetLogicalDrives()[0], Path.GetFileName(this._url));
wc.DownloadFile(this._url, localFileName);
}
catch { }
}
}
עכשיו בואו נניח שאנחנו רוצים לדעת בכל רגע מה קורה עם ה Threadים שלנו. ניתן ליצור פונקציה סטטית בתוכנית הראשית (או לא סטטית ולהעביר לכל Thread הפניה לתוכנית הראשית) ואז הם יוכלו לקרוא לפונקציה הזאת כדי להודיע מה קורה איתם. כמובן שיש לדאוג שהם לא ידרסו נתונים אחד של השני... יש עוד הרבה לדבר על MultiThreading אז נמשיך בחלק אחר
להורדת הקוד
Be the first to rate this post
- Currently 0/5 Stars.
- 1
- 2
- 3
- 4
- 5