Most popular

วันพุธที่ 18 พฤษภาคม พ.ศ. 2554

delegate & Invoke ทำ Process จับฉ่าย ประมวลผลพร้อมกันในคราวเดียว

บางครั้งโปรแกรมที่เราต้องพัฒนาอาจจะมีความจำเป็นในการดึงประสิทธิ์ภาพของ Processor ในการประมวลผลมากที่สุด จำเป็นต้องใช้งาน Invoke
การใช้ Invoke กับ delegate เป็นตัวอย่างที่ดีที่สุด เพราะง่ายและชัดเจน ซึ่งเป็นวิธีที่ผู้เขียนใช้ทดสอบ
ตัวของ delegate method ที่มีการใช้ BeginInvoke นั้นจะสามารถทำงานพร้อมๆกันหลายๆ method ได้ โดยที่ไม่มีการรอกัน เป็นการทำงาน Multi-Threading อีกแบบนึงที่ใช้ได้ดี คำสั่ง BeginInvoke จะทำการแยก Thread ออกจาก Common Language Runtime (CLR) และโดนจัดการด้วย Thread pool จึงทำให้แต่ละ delegate method ทำงานได้อย่างอิสระต่อกัน และ Thread ที่เกิดจากการใช้ Invoke สามารถมีได้ถึง 25 Thread ในการทำงานพร้อมกันบน Processor ตัวเดียว

ผู้เขียนได้ออกแบบฟอร์มเพื่อทดสอบตามรูปด้านล่างนี้

การทำงานของโปรแกรมก็คือ เมื่อกดปุ่ม Run จะให้มีการวนลูปสุ่มชื่อเพื่อน เข้าไปใน ListBox โดยที่ ListBox ด้านขวามือจะให้ "Hello" ส่วนด้านซ้ายมือจะให้ "Bye"
ในส่วน Member ของ Class Form1 ผู้เขียนจะประกาศ delegate method และรายชื่อของเพื่อนในรูปแบบ array

private delegate void showMS(string txt,ListBox l);

private string[] friends = {
"David","Ryan","Adam","Briony","Harry","Sara",
"Peter","Maria","Natacha","Lydia","Nina","Macha",
"Maggy","Victoria","Naomi"
};

ต่อมาคือ method ที่ใช้กับ delegate ที่ประกาศไว้
method นี้จะมี Parameter 2 ตัวคือ string และ ListBox
private void mess(string str,ListBox lb)
{
       lb.Items.Clear();  //ล้าง ListBox
       int i=0;
       while (i < 2000)
       {
             //สุ่มชื่อเพื่อนขึ้นมา
             string fName = friends[new Random().Next(0, friends.Length)]; 
             lb.Items.Add(str + " " + fName);
             lb.SelectedIndex = i;
             i++;
       }
}

จากนั้นก็มาถึงคำสั่งที่ใช้กับปุุ่ม Run (button1)
โดยเมื่อมีการกดปุ่มแล้วจะมีการใส่ค่าลงใน ListBox ทั้ง 2 ตัวพร้อมกัน

private void button1_Click(object sender, EventArgs e)
{
       //ปิดการตรวจสอบ Thread Cross
       Form1.CheckForIllegalCrossThreadCalls = false;
       //สร้าง delegate method
       showMS sms = new showMS(mess);

       //ประกาศ   IAsyncResult  เพื่อรับค่าสถานะจาก delegate ที่มีการ invoke
       IAsyncResult helloRes = sms.BeginInvoke("Hello", this.listBox1, null, null);
       IAsyncResult byeRes = sms.BeginInvoke("Bye", this.listBox2, null, null);
}
เมื่อลองรันโปรแกรมและกดปุ่ม Run ก็จะมีการใส่ค่าใน ListBox ทั้ง 2 ตัวพร้อมๆกัน


ผู้เขียนจะสร้าง Method เพิ่มเติมเพื่อให้ทำงานเมื่อจากมีการ Callback กลับมาจากการ Invoke
  • Method helloCallback : เมื่อมีการ Callback ให้แสดงข้อความ "Completed"
  • Method byeCallback : เมื่อมีการ Callback ให้ทำงานซ้ำอีกรอบ และ Callback ไปที่ helloCallback
private void helloCallback(IAsyncResult res)
{
        MessageBox.Show("Completed");
}

private void byeCallback(IAsyncResult res)
{
        showMS sms = new showMS(mess);
        IAsyncResult byeRes = sms.BeginInvoke("Bye", this.listBox2, helloCallback, null);
}

และแก้ไข Code ในปุ่ม Run(button1) ให้ Invoke มี Parameter ที่เรียกใช้ Callback method
private void button1_Click(object sender, EventArgs e)
{
       Form1.CheckForIllegalCrossThreadCalls = false;
       showMS sms = new showMS(mess);
       
IAsyncResult helloRes = sms.BeginInvoke("Hello", this.listBox1, helloCallback, null);
       IAsyncResult byeRes = sms.BeginInvoke("Bye", this.listBox2, byeCallback, null);

}


จากนั้นลองทดสอบอีกครั้งจะพบว่ามีการทำงานทั้งหมด 3 รอบ คือ ใส่ข้อมูลใน ListBox คือ Hello 1 รอบ และ Bye 1 รอบ และหลังจาก ListBox ฝั่งซ้ายทำงานเสร็จสิ้นจนมีการ Callback จะทำงานต่ออีก 1 รอบก่อนที่จะจบ โดยทำงานไม่รอกัน

หมายเหตุ
(IAsyncResult helloRes = sms.BeginInvoke("Hello", this.listBox1, helloCallback, null);
IAsyncResult byeRes = sms.BeginInvoke("Bye", this.listBox2, byeCallback, null);

ค่าสถานะที่ได้รับจากการ Invoke มีรายละเอียดคือ
  • AsyncState : สถานะการทำงานที่ต่างกันออกไป
  • AsyncWaitHandle  : รอ และปกป้องให้การทำงานที่ต่างกันสำเร็จ
  • CompleteSynchronously  : บ่งบอกว่าการทำงานที่ต่างๆกันนั้นสำเร็จ
  • IsCompleted : บ่งบอกว่าการทำงานทั้งหมดเสร็จสิ้นแล้ว

1 ความคิดเห็น:

  1. ไม่ระบุชื่อ2 สิงหาคม 2556 เวลา 14:21

    ขอโค้ดตัวอย่างหน่อยได้ไหมครับ

    ตอบลบ