Parallel Programming with C# for Multicore Processor

ถ้าจะกล่าวถึงประวัติสถาปัตยกรรมคอมพิวเตอร์ เครื่องคอมพิวเตอร์ส่วนบุคคลเครื่องแรกที่ผมได้เคยใช้คือ 8086/8088 บนเครื่อง IBM/PC Compatible ต่อมาได้มีพัฒนาการต่อกลายเป็น 80286, 80386, 80486 รุ่นต่อไปที่น่าจะเป็น 80586 บริษัทอินเทลก็ได้เปลี่ยนชื่อทางการตลาดว่า Pentium (Penta แปลว่า 5) ต่อมาก็เป็น Pentium II, Pentium III, Pentium 4 ก็เป็นอันสิ้นสุดยุคของ CPU แบบ Single Core ต่อมาก็เข้าสู่ยุคของ Duo-Core และ Multicore CPU ตระกูล Hyper-Threading, Core 2 Duo, Core i3, Core i5, Core i7

จากที่กล่าวมานั่นหมายความว่าเรากำลังอยู่ในยุคของ Multicore Processor กันมานานแล้ว แต่การเขียนโปรแกรมของบางคนยังเขียนแบบ Single Core กันอยู่เลย ยังใช้ประโยชน์จาก Multicore กันไม่ได้มาก

ตั้งแต่ Microsoft .NET Framework 4 (จนถึงปัจจุบันรวม .NET Core ด้วย) ได้ออกฟีเจอร์ใหม่คือ Parallel Programming mode ที่จะช่วยให้เราใช้ประโยชน์จาก CPU ทุก Core และรันโปรแกรมแบบขนานหรือ Parallel ได้

บทความนี้ผมจะมาสอนเทคนิค เปลี่ยนรูปแบบการเขียนเพียงเล็กน้อย ก็จะทำให้โปรแกรมของเรามีประสิทธิภาพการทำงานที่ดีขึ้นอย่างเห็นได้ชัด

1. คำสั่งวนลูป for

ตัวอย่าง ทดสอบการวนลูป 100 รอบ (และสั่งหยุด 200 ms เพื่อให้เรามองเห็นชัด)

for (int i = 0; i < 100; i++) {
    Console.Write("{0} ", i);
    Thread.Sleep(200);
}

ผลที่ได้คือโปรแกรมจะวิ่งวนลูปทีละลูปจนครบ ซึ่งถ้าเราดูตามนี้จะเห็นได้ว่าถึงแม้เราจะมี CPU แบบ Multicore ก็ไม่ได้ช่วยทำให้โปรแกรมนี้ทำงานได้เร็วขึ้นเลย


เปลี่ยนมาใช้ Parallel.For แทน for สิ

Parallel.For อยู่ในเนมสเปซ System.Threading.Tasks

using System.Threading.Tasks;

เปลี่ยนมาเขียนแบบนี้แทน

Parallel.For(0, 100, i => {
    Console.Write("{0} ", i);
    Thread.Sleep(200);
});

จะเห็นได้ว่าการวนลูปนี้ ตัวเลขจะไม่ได้ทำแบบเรียงลำดับ เพราะมันจะส่งงานกระจายไปให้กับ CPU ทุกๆ Core ที่มีอยู่ แล้วทำพร้อมๆกัน จนครบ 100 รอบ แต่งานเสร็จไวกว่าเดิมมาก


2. คำสั่งวนลูป foreach

ตัวอย่าง มีตัวอักษรอยู่ใน List คือ A - Z ต้องการวนลูปแสดงตัวอักษรออกมา

var names = new List<string>{ "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" };

foreach สามารถเขียนได้ 2 รูปแบบคือ

foreach (var n in names) {
    Console.Write("{0} ", n);
    Thread.Sleep(200);
}

หรือ

names.ForEach(n => {
    Console.Write("{0} ", n);
    Thread.Sleep(200);
});

ผลที่ได้ก็จะเหมือนกันคือโปรแกรมจะวิ่งวนลูปทีละลูปจนครบเหมือนกับ for ที่ใช้เพียงแค่ Single Core เท่านั้น


เปลี่ยนมาใช้ Parallel.ForEach แทน foreach สิ

Parallel.ForEach(names, n => {
    Console.Write("{0} ", n);
    Thread.Sleep(200);
});

หรือเขียนในรูปแบบของ Linq แบบนี้ก็ได้

names.AsParallel().ForAll(n => {
    Console.Write("{0} ", n);
    Thread.Sleep(200);
});

จะเห็นได้ว่าการวนลูปนี้ ตัวอักษรจะไม่ได้ทำแบบเรียงลำดับ เพราะมันจะส่งงานกระจายไปให้กับ CPU ทุกๆ Core ที่มีอยู่ แล้วทำพร้อมๆกันจนครบ แต่งานเสร็จไวกว่าเดิมมาก


Source: https://www.c-sharpcorner.com/article/parallel-programming-in-c-sharp-to-leverage-multicore-processor

Donate ให้กับ CodeBangkok ได้ที่
BTC = 3GDxhb84ho2jmAV9seAgAFJ7dy1XR3GCyc
ETH = 0x119fa8A618A0283D1834853325A8FF4fe1101230
LTC = ME2abSdDeQYuTmzZSAnHL7LGGeF836d1ut
ZEC = t1Y4NkK3Dx3yBbwCVdpXzKYrqUSJSHgaFXa

1 Like