Tags: | Categories: C# Posted by talgiladi on 11/29/2007 9:50 AM | Comments (5)

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

static List<int> myNums; public static void AddNumber(int num) { if (!myNums.Contains(num))-->check { myNums.Add(num);-->add } }

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

  1. להפוך את כל הפונקציה ל Synchronized - משמע שסביבת הריצה לא תיתן ליותר מ Thread אחד לגשת לפונקציה במקביל
  2. לנעול את האובייקט הבעייתי, שבמקרה שלנו זה myNums
  3. להשתמש באמצעים קיצוניים יותר :)

בואו נראה איך ליישם 2 שיטות בדוגמה שלנו - כדי לישם את השיטה הראשונה פשוט נוסיף הוראה לפני הגדרת הפונקציה:

[MethodImpl(MethodImplOptions.Synchronized)]

כדי ליישם את השיטה השניה נוסיף שורה אחת בתוך הפונקציה:

static List<int> myNums;
public static void AddNumber(int num)
{
lock(myNums)
{
if (!myNums.Contains(num))-->check
{
myNums.Add(num);-->add
}
}
}

וכל עוד אנחנו בתוך הקטע שנועל את האובייקט, אף Thread לא יוכל לגשת אליו

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

עדיפות:
ניתן לקבוע לכל Thread שאנו מתחילים את העדיפות שלו - איזה חלק הוא יקבל מהמעבד באופן יחסי

t.Priority = ThreadPriority.Normal;

לסיכום בואו נראה דוגמה של Crawler MultiThreaded , התוכנית שלנו רוצה להריץ עד 10 Threading במקביל, הם יגלשו באינטרנט, יאספו לינקים, כל אחד מדף אחד, ויפסיקו, ואז יתחיל Thread חדש, יקבל לינק אחד ממה שאספנו וימשיך לקרוא לינקים ממנו
סוגיות:

  • אני חייב להשתמש ב MultiThreading כי חבל להתעכב עד שכל שרת יענה לי, אם הוא יענה בכלל, גם חבל על זמן שבו אני מוצא את הלינקים בדף
  • אני רוצה שמספר ה Threading שרצים במקביל לא יהיה גדול מ-10 בגלל רוחב הפס לאינטרנט וכדי לא להעמיס על המעבד
  • אני רוצה להימנע ממצב ששני Threading יכניסו את אותו הלינק למאגר הלינקים ואז אני אבקר באותו לינק פעמיים סתם

יהיו לנו 2 מחלקות - הראשית שמריצה את ה Threadים, ומחלקה שתייצג את ה Thread והיא זאת שתפתח את דף האינטרנט, תקרא את הקישורים ותוסיף אותם לאוסף שימצא במחלקה הראשית שלנו

שם המחלקה הראשית Crawler
המחלקה תכיל משתנה סטטי מסוג int שיבדוק כמה טרדים כרגע פעילים

private static int threadsCount;

המחלקה גם תכיל רשימה סטטית של כל הלינקים החדשים

private static Queue<string> links;

המחלקה מכילה פונקציה שמאפשרת ל Thread שסיים להודיע שהוא סיים ובכך מוריד את מספר הThreadים הפעילים

[MethodImpl( MethodImplOptions.Synchronized)]
internal static void RemoveThread()
{
    threadsCount--;
}

ופונקציה שאליה יעבירו כל הThreadים את כל הלינקים שמצאו בדף כדי לעדכן את רשימת הלינקים החדשים שיש לנו

internal static void AddLinks(Queue<string> newlinks)
{
    lock (links)   
    {
        for (int i = 0; i < newlinks.Count; i++)
        {
            links.Enqueue(newlinks.Dequeue);
        }
    }
}

והלולאה העיקרית שמריצה את כל ה Threadים

private void Start()
{
links = new Queue<string>();
links.Enqueue("http://www.google.com/search?q=csharp");
run = true;
while (run)
{
while (threadsCount >= 10)
{
Thread.Sleep(1000);
}
while (links.Count == 0)
{
Thread.Sleep(1000);
}
WorkerThread wt = new WorkerThread(links.Dequeue);
Thread t = new Thread(new ThreadStart(wt.Run));
threadsCount++;
t.Start();
}
}

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

ונשארה לנו רק המחלקה WorkerThread שהמבנה שלה לא כל משנה בעצם

public class WorkerThread
{
private string _url;
public WorkerThread(string url)
{
this._url = url;
}
public void Run()
{
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(this._url);
HttpWebResponse resp = req.GetRequestStream();
if (resp.StatusCode == HttpStatusCode.OK)
{
string data = new StringReader(resp.GetResponseStream()).ReadToEnd();
resp.Close();
Queue<string> links = new Queue<string>();
//do the formatting of the page to find links...
Crawler.AddLinks(links);
}
Crawler.RemoveThread();
}
}

המחלקה שומרת את הכתובת שהיא קיבלה מהמחלקה הראשית שלנו, ואז בפונקציה Run שגם מופעלת על ידי המחלקה הראשית היא מבצעת פניה לדף, מפרמטת אותו כדי לחפש את הלינקים שם, קוראת לפונקציה ססטית במחלקה הראשית כדי להוסיף את הלינקים שנמצאו, ובסוף גם מורידה את מספר הThreadים הפעילים במחלקה הראשית

Technorati Tags:

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags: , | Categories: C# Posted by talgiladi on 11/19/2007 8:59 PM | Comments (13)

ישנן 2 דרכים עיקריות השונות במהותן לעבודה עם xml. יש את השימוש ב XmlDocument ששם בעצם אנו קוראים את כל הקובץ לזיכרון ואז מתחילים לעבוד ויש את השיטה של Reader שבה אנו בעצם קוראים שורה שורה מהקובץ, יש הרבה מידע בגוגל מי שירצה יראה, בואו רק נראה את הקוד הפשוט לקריאת xml באמצעות reader

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

string myXml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<bookstore>" +
"<book isbn=\"23534\">" +
"<name>book1</name>" +
"<price>34</price>" +
"</book>" +
"<book isbn=\"9999\">" +
"<name>book2</name>" +
"<price>71</price>" +
"</book>" +
"</bookstore>";

XmlTextReader לא יודע לקרוא מידע מסטרינג ולכן נשתמש ב StringReader שמקבל כפרמטר את הסטרינג שלנו

System.IO.StringReader sr = new S System.IO.StringReader(myXml);
System.Xml.XmlTextReader reader = new System.Xml.XmlTextReader(sr);

ואפשר להתחיל לקרוא...

while (reader.Read()) { }

הלולאה תרוץ עד שלא יהיה לו מה לקרוא

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

if (reader.NodeType == System.Xml.XmlNodeType.Element)
{
}

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

if (reader.Name == "book")
{
}

וכעת נשווה את המאפיין שאנו רוצים

if (reader.AttributeCount > 0 && reader.GetAttribute("isbn")=="9999")
{
}

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

System.Xml.XmlReader subReader = reader.ReadSubtree();

ונרוץ עליו כמו שרצנו על ה reader הכללי:

while (subReader.Read())
{
    if (subReader.NodeType == System.Xml.XmlNodeType.Element)
    {
        switch (subReader.Name)
        {
            case "name":
                Console.WriteLine("Book name : " + subReader.ReadString());
                break;
            case "price":
                Console.WriteLine("Book price : " + subReader.ReadString());
                break;
            }
        }
}

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

להורדת הפרוייקט

Technorati Tags: ,

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

RSS

Tags: | Categories: C# Posted by talgiladi on 11/11/2007 7:00 PM | Comments (3)

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

בואו נתחיל ביצירת דף חדש שהוא יהיה הכתובת ל RSS. בעת פניה לדף אנו בסך הכל רוצים להדפיס בחזרה את קובץ ה xml וקורא ה rss כבר ידע מה לעשות איתו. מבנה הקובץ הוא סטנדרטי כמובן ובצורה הבאה:

<rss version="2.0">
    <channel>
        <title>coding games</title>
        <link>http://www.talgiladi.net</link>
        <description>code samples </description>
        <ttl>180</ttl>
        <item>
            <title><![CDATA[Creating xml documents with xml text writer]]></title>
            <link>http://www.talgiladi.net/XmlTextWriter.aspx</link>
            <guid isPermaLink="true">http://www.talgiladi.net/XmlTextWriter.aspx</guid>
            <description><![CDATA[xml text writer for fast and easy creation of xml documents]]></description>
            <pubDate>2/5/2008 9:24:18 PM</pubDate>
        </item>
</channel>
</rss>

כשהכותרת הראשונה היא שם הערוץ שלכם, אחר כך הכתובת שלו כמובן, תיאור, וכמה זמן קורא ה RSS יכול לשמור בזיכרון את המידע לפני שהוא יפנה אליכם שוב לקבל רשימה חדשה.
אחר כך מתחילות הכתבות עצמן - כל item הוא כתבה נפרדת שיש לה כותרת, לינק, מזהה יחודי, שבמקרה שלי זה הלינק, תיאור וזמן המאמר. זהו, עבור כל מאמר מוסיפים item חדש ויש לנו רשימה...

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

כמו כן צריך להוסיף את המשפט :

Response.ContentType = "text/xml";

כך שיהיה מובן שאנו שולחים קובץ xml בחזרה ולא html

באתר שלנו ניתן לשים לינק לדף הזה וכאשר יקליקו עליו הדפדפן כבר יבין שמדובר ב RSS וישאל את המשתמש האם הוא רוצה להירשם לערוץ הזה

דבר אחרון אבל לא חובה, אם אנחנו רוצים שהדפדפן יציג לבד את הסמל הכתום הזה של RSS כשהוא מגיע לדף שלנו עוד לפני שהמשתמש לחץ על הלינק,

 browser_rss

צריך להוסיף שורה ב head של האתר כדי שהדפדפן יזהה שיש כאן RSS

<link rel="alternate" type="application/rss+xml" title="talgiladi.net articles" href="http://www.talgiladi.net/RssArticlesReader.ashx" />

להורדת פרוייקט דוגמה

Technorati Tags:

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags: | Categories: C# Posted by talgiladi on 11/2/2007 10:00 AM | Comments (12)

IsolatedStorage

כשהאפלקציה שלנו רצה על מחשב של לקוח, אנו רוצים לעיתים לשמור קבצים על הכונן הקשיח.

אז ישנה את השיטה הרגילה של פשוט לשמור קובץ בספריה שבה האפליקציה שלנו רצה או בכל מקום אחר בדיסק הקשיח,

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

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

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

ג. פחות סיכוי שאפליקציה אחרת תוכל להשחית את המידע ששמרנו

 

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

מפיץ הקוד או האתר שממנו הוא הגיע, וכך בעצם רק לאפליקציה שלנו יש גישה למידע הזה.

(כדי להשתמש במחלקות יש להוסיף using System.IO.IsolatedStorage במחלקה)

קודם כל ניצור הפניה לאובייקט דרך הפונקציה הסטטית:

IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForAssembly();

כעת ניתן ליצור ספריה:

isf.CreateDirectory("temp3");

וליצור קובץ ולפתוח אותו:

IsolatedStorageFileStream isfs = new IsolatedStorageFileStream("temp3\\myfile.txt", FileMode.OpenOrCreate, isf);

וכעת ניתן לעבוד איתו כרגיל כמו עם כל הקבצים :

StreamReader sr = new StreamReader(isfs);

 

isfs.WriteByte((byte)84);

 

isfs.Close();

Technorati Tags:

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5