การใช้ Thread ก็คือการแยกกระบวนการทำงานออกจากกัน จากที่โปรแกรมเคยทำงานเป็นลำดับ Thread ก็เหมือนทางลัด แยกไปอีกทาง และในที่สุดก็กลับมาบรรจบกันที่ปลายทาง หรืออาจจะเดินกันเป็นแบบเส้นขนานก็ได้ แต่ที่สำคัญคือ การไม่จำกัดการทำงานอยู่เพียงแค่ Process หลักเพียงอย่างเดียว
ผลที่ได้คือการทำงานที่รวดเร็วมากขึ้น และช่วยให้ Process หลัก มี Performance ที่ดีขึ้น
หากท่านผู้;;อ่านไม่เคยศึกษาเรื่อง Thread มาเลยขอแนะนำให้ลองค้นหาจาก Google ดูก่อน ซึ่งหลายๆเว็บก็อธิบายได้เป็นอย่างดีสำหรับหลักการทำงาน แต่กรณีที่ผู้เขียนกำลังจะเขียนนี้เป็นการใช้ Thread จริง ใช้งานจริงไม่มีตัวแสดงแทน กับการนำ Thread มาใช้กับโปรแกรมแบบที่มี User Interface ที่ทุกคนก็มักจะเขียนกัน
ผู้เขียนเองก็ประสบปัญหากับการนำเอา Thread มาใช้ไม่น้อย Thread ของ .Net นั้นค่อนข้างจะแยกกันอย่างชัดเจน หากจะใช้กับ UI ก็ต้องใช้เทคนิคอย่าง delegate เข้าช่วยด้วย
ผู้เขียนได้พบการเขียนหลายรูปแบบซึ่งสามารถใช้ได้เหมือนกัน การ Design Code บางแบบก็เขียนง่าย เข้าใจง่าย บางแบบก็ย่อเสียจน...
ฟอร์มทดสอบที่ผู้เขียนสร้างขึ้นง่ายๆ มีเพียง Button และ ListBox
โดยการทำงานคือ กดปุ่มเพื่อให้ Thread ทำงานใส่ข้อมูลเข้าไปใน ListBox นั่นเอง
แบบแรกเป็นแบบที่ผู้เขียนคิดว่าเข้าใจง่ายแล้ว
private delegate void AddListBoxItemDelegate(object item); //ประกาศ delegate
private void AddListBoxItem(object item) //method ที่ delegate ชี้มา
{
if (this.listBox1.InvokeRequired) //Control เกิดเรียก Invoke เข้ามา
{
//เรียกใช้ method ผ่าน delegate ซ้ำ
this.listBox1.Invoke(new AddListBoxItemDelegate(this.AddListBoxItem), item);
}
else
{ //ในกรณีที่ไม่มีการเรียก Invoke แล้วให้ดำเนินการกับ Control ได้เลย
this.listBox1.Items.Add(item);
fillList();
}
}
void fillList() //method วนลูปให้ Listbox
{
int i = 0;
while (true)
{
i++;
listBox1.Items.Add(i);
if (i == 4000)
break;
}
}
private void button1_Click(object sender, EventArgs e) //event on click ปุ่ม start
{
//ประกาศ thread instance ให้ทำงานกับ method AddListBoxItem
Thread t = new Thread(AddListBoxItem);
t.Start("Test"); //ให้ thread พร้อมส่ง paramerter เพื่อทดสอบ
}
ทดสอบรันโปรแกรมแล้วกดปุ่ม Start ได้ผลลัพถูกต้องตามภาพ
รูปแบบที่สองที่สามารถใช้ได้เช่นกัน แต่จะมีความชัดเจนกว่าในการประกาศ และเรียกใช้ Instance
โดยที่จะประกาศ delegate type ไว้เป็น member ของ class
public delegate void addToList(); //ประกาศไทป์; delegate
public addToList add; //ประกาศ instance ของ delegate
ต่อมาจะทำการสร้าง delegate ขึ้นมาใช้ ในที่นี้ผู้เขียนสร้างที่ Constructor ของ Form
public Form1()
{
InitializeComponent();
add = new addToList(fillList); // delegate add เรียก method signature ในที่นี้คือ fillList
}
ปรับปรุง method fillList เล็กน้อย
void fillList()
{
if (listBox1.InvokeRequired)
{
listBox1.Invoke(add);
}
else
{
int i = 0;
while (true)
{
i++;
listBox1.Items.Add(i);
if (i == 4000)
break;
}
}
}
การเรียกใช้งาน Thread ในปุ่ม Start
ต่างกับ Code แบบแรกตรงที่ method fillList ไม่มี Parameter ส่งเข้ามา
private void button1_Click(object sender, EventArgs e)
{
//การประกาศให้ Thread ใช้ method fillList แต่ต้องเรียกใช้โดยผ่าน delegate add
Thread t = new Thread(add.Invoke);
t.Start();
}
แบบที่สาม คือการย่อให้กระชับ Code ลงมาให้น้อยลง โดย Anonymous method แต่ก็แน่นอนว่าจะต้องเสียความยืดหยุ่นไป ต่างจากสองแบบแรกที่ได้ยกตัวอย่างไป
โดยการเข้าไปจัดการโครงสร้างของ method fillList เสียใหม่ให้เป็นแบบนี้
void fillList()
{
Invoke((MethodInvoker)delegate {
int i = 0;
while (true)
{
i++;
listBox1.Items.Add(i);
if (i == 4000)
break;
}
});
}
จากนั้นก็เรียกใช้เหมือนเดิม แต่เปลี่ยนจากการที่ต้องอ้าง method ผ่าน delegate ก็ไม่ต้องอ้อมค้อม เรียกใช้กันตรงๆเลย
private void button1_Click(object sender, EventArgs e)
{
//อ้าง method fillList ให้กับ thread ได้เลย
Thread t = new Thread(fillList);
t.Start();
}
แบบที่สี่ คราวนี้เราจะปลดการตรวจสอบ Cross Thread ของ .Net Framework ออกเพื่อจะได้ทำงานได้สะดวกขึ้น
ตามหลักการที่เป็นมาตรฐานใน .Net Thread ห้ามทำงานมั่วกัน หมายถึงหากมีฟอร์มหนึ่งรันขึ้นมาจะถือเป็น 1 Thread อยู่แล้ว ฉนั้นโปรแกรมแบบ GUI เมื่อรันขึ้นมาก็จะเป็น 1 Thread Control ทุกตัวก็จะถือว่าอยู่บน Thread ที่ 1 ทันที จะเห็นได้ว่าหากพยายามนำ Control ไปใช้$51;น Thread ที่ได้สร้างขึ้นมาให$17;่ จะเกิด Error เกี่ยวกับ Cross Thread จึงต้องบ่งชี้การทำงานแบบเลี่ยงๆโดยใช้ delegate เข้ามาช่วย
(ซึ่งในภาษาอื่นอย่าง Delphi ค่าเริ่มต้นสามารถเขียน Thread แบบ Cross ได้ แต่ใน .Net ค่าเริ่มต้น การเขียนแบบ Cross จะไม่ยอมให้)
ผู้เขียนจึงดัดแปลง Code ให้เป็นแบบง่ายๆ โดยเปลี่ยน method fillList เป็น
void fillList()
{
int i = 0;
while (true)
{
i++;
listBox1.Items.Add(i);
if (i == 4000)
break;
}
}
private void button1_Click(object sender, EventArgs e)
{
//ปลดการตรวจสอบ Cross Thread บน Form1
Form1.CheckForIllegalCrossThreadCalls = false;
Thread t = new Thread(fillList); //ให้ Thread ทำงานกับ method fillList อย่างชิวๆ
t.Start();
}
จะเห็นได้ว่าพอปลดการตรวจสอบ Cross Thread ออกแล้ว โปรแกรมก็จะไม่ต้องยุ่งกับ delegate อีกต่อไป
แต่ถ้าถามว่าดีหรือไม่ ผู้เขียนคิดว่าคงเหมือนกับการเดินข้ามถนนโดยใช้สะพ;านลอย หรือ ไม่ใช้สะพานลอยก็ได้ ความเป็นระเบียบและความปลอดภัย ก็ย่อมต่างกัน
แบบที่ห้า เขียนแบบโคตรย่อ ปิดการตรวจสอบ Cross Thread แล้วยังจะใช้ delegate ด้วย การเขียนแบบนี้ดีในการกระชับ Code ใช้ Anonymous method แต่ต้องระวังเกี่ยวกับความยืดหยุ่นในการทำงาน หากแน่ใจว่ามีการทำงานที่นี่ ที่เดียวจบก็ลุยเลย
private void button1_Click(object sender, EventArgs e)
{
//ปลดการตรวจสอบ Cross Thread บน Form1
Form1.CheckForIllegalCrossThreadCalls = false;
//สร้าง Thread พร้อมกับยัดเยียด delegate method เข้าไปใน Constructor เลย
Thread t = new Thread(delegate() {
int i = 0;
while (true)
{
i++;
listBox1.Items.Add(i);
if (i == 4000)
break;
}
});
t.Start();
}
คงพอเข้าใจกันแล้วว่าการสร้าง และใช้ Thread กับพวก Control นั้นเป็นอย่างไร
ผู้เขียนหวังว่าคงจะเป็นประโยชน์ต่อผู้อ่านไม่มากก็น้อย ซึ่งส่วนใหญ่ Thread จะนำไปใช้กับการเขียนโปรแกรมในรูปแบบของเกมหรือกราฟฟิค แต่ถึงกระนั้นหากผู้อ่านนำไปประยุคใช้แม้ในโปรแกรมทาง Database หรือ BI โปรแกรมของท่านก็จะมีประสิทธิภาพสูงยิ่งขึ้น
Most popular
-
Trigger คืออะไร? ท่านที่เคยเขียนโปรแกรม และเคยใช้ Event handle ก็จะนึกถึงการทำงานของ Trigger ไม่ยาก Trigger ก็คือ Code คำสั่ง SQL ที่ถูกสร...
-
MySQL Workbench ที่ผู้เขียนใช้ทำตัวอย่างเป็น Version 5.2.34 CE สำหรับ Windows 32 bit หรือตัวใหม่กว่าก็ได้ครับ ดาวน์โหลดได้ที่นี่ http://www...
-
คนที่มีภาพใน facebook เยอะๆก็คงจะต้องการย้ายภาพไปมา บางทีก็เอาภาพบนกระดานเก็บลงอัลบั้ม บางทีก็หาไม่เจอว่าจะย้ายได้ยังไง การย้ายอัลบั้มไม่ยา...
-
Tier คำนี้เมื่อแปลออกมาจะแปลได้ว่า "ชั้น" Tier ในวงการ Software ก็มีความหมายคล้ายกัน สำหรับท่านที่ยังไม่เข้าใจขอแนะนำง่ายๆ โดยให้...
-
ในการเขียนโปรแกรมแบบ OOP นั้น แน่นอนว่าจะต้องเจอคำว่า Object กันจนแทบจะเบื่อไปเลย บางทีอาจจะติดปากเรียกโน่น นี่ นั่นว่า Object ในชีวิตประจำว...
วันอาทิตย์ที่ 1 พฤษภาคม พ.ศ. 2554
ประยุคใช้ C# Threading แยก Process การทำงานของโปรแกรมแบบ GUI
สมัครสมาชิก:
ส่งความคิดเห็น (Atom)
CheckForIllegalCrossThreadCalls มันคืออะไรนะครับ
ตอบลบ