เขียนโปรแกรมแบบ Parallel ด้วย MPI – ตอนที่2 ให้คอมแต่ละเครื่องคุยกันด้วย Send & Receive

อ่านตอนก่อนๆ ได้ที่ #Parallel

ใน ตอนที่ 1 เราพูดถึงการใช้ MPI และโครงสร้างแบบ Master-Slave ไปแล้ว โดยคอนเซ็ปของการเขียนโปรแกรมแบบพาราเรล Message Passing นั่นจะต้องมีการคุยกันระหว่างโปรเซส

วิธีง่ายที่สุดคือใช้คำสั่ง MPI_Send (สำหรับคนส่งข้อมูล) และ MPI_Recv (สำหรับคนรับข้อมูล)

แต่! ถึงจะบอกว่าส่งข้อมูลไปให้อีกโปรเซสหนึ่ง มันก็ไม่ได้ส่งเป็นข้อความอะไรหรอกนะ แต่ส่งเป็น "value" ไปตั้งหากล่ะ

อย่าง เช่น Process 0 กำลังถือค่า 100 อยู่ซึ่งเก็บอยู่ในตัวแปร X ละกัน ถ้ามันอยากส่งค่า 100 นี่ไปให้ Process 1 ... เจ้า Process 1 นี่เป็นคนรับข้อมูลก็ต้องบอกด้วยว่าค่า 100 ที่รับมาจาก Process 0 เมื่อกี้น่ะ จะให้วางไว้ในตัวแปรอะไร

MPI_Send( ตัวที่จะส่ง, ขนาด, ชนิดข้อมูล, ส่งให้ใคร, tag, MPI_COMM_WORLD ) 

ใช้ สำหรับคนที่ต้องการจะส่งข้อมูล โดยต้องบอกว่าจะส่งตัวแปรอะไรไป และตัวแปรตัวนั้นน่ะมันเป็นอะไร (เช่น int double char) ขนาดกี่ตัวและส่งไปให้ใคร

MPI_Recv( ตัวที่จะรับ, ขนาด, ชนิดข้อมูล, รับจากใคร, tag, MPI_COMM_WORLD, status)


เมื่อมีคนส่งก็ต้องมีคนรับ ส่งใหญ่โค้ดชุดนี้ก็จะวางไว้ในส่วนของโปรเซสที่คนเรียก MPI_Send ส่งไปหา

ทั้ง 2 คำสั่งจำเป็นต้องบอกว่าหมายเลขโปรเซสที่ส่งไปให้น่ะ มันอยู่ในกลุ่มคอมพิวเตอร์ชุดไหน ซึ่งเราใช้ MPI_COMM_WORLD เป็นตัวบอก

ส่วน tag เป็นเลขที่ต้องใส่ให้ตรงกันทั้งคนส่งและคนรับ ถ้าไม่ตรงกันจะถือว่าการส่งนี้ส่งไม่ได้นะ

สำหรับ MPI_Recv จะมี parameter มากกว่า MPI_Send 1 ตัวคือต้องเพิ่ม status เข้ามาเพื่อบอกว่าการส่งข้อมูลสำเร็จป่ะ?

มาดูตัวอย่างการเขียนโค้ดกันเลยดีกว่า

int rank;
MPI_Status status;
MPI_Init( &argc, &argv );
MPI_Comm_rank( MPI_COMM_WORLD, &rank );

int x = 10, y = 20;

if( rank == 0 ){
    x = 100;
    MPI_Send( &x, 1, MPI_INT, 1, 123, MPI_COMM_WORLD );
}
else if( rank == 1 ){
    MPI_Send( &y, 1, MPI_INT, 0, 123, MPI_COMM_WORLD, &status );
}

อธิบายโค้ดกันหน่อย

เราเริ่มกันด้วยการประกาศตัวแปร  int x = 10, y = 20;  ขึ้นมา แต่อย่างที่บอกไปในตอนที่แล้ว การเรียก MPI_Init() นั้นเป็นการสั่งว่าโค้ดตั้งแต่ตรงนี้เป็นต้นไปเราจะคิดแบบพาราเรล


ดังนั้น ค่า x และ y จะถือว่าโปรเซสแต่ละตัวถือแยกกัน ไม่เกี่ยวกันเลย

จากรูป เราจะเห็นว่าทั้ง Process 0 และ Process 1 มีค่า x กับ y เป็นของตัวเองเลย ไม่แชร์กันเลย

หลัง จากนั้นเราก็ใช้รูปแบบของการสั่งงานแบบ Master-Slave คือใช้ if-else เช็กกันเลยว่าถ้า rank เป็น 0 ให้ทำงานแบบนี้ ถ้าเป็น 1 ให้ทำงานแบบนี้ๆ

Process 0 เลยทำการสั่งให้เปลี่ยนค่า x = 100 ... ในจังหวะนี้ ค่า x ที่เก็บอยู่ใน Process 1 จะยังเป็นค่าเดิม ไม่เปลี่ยนแปลง

ส่วนคำสั่งต่อไป (ทุกโปรเซสจะทำงานไปพร้อมๆ กัน) คือ Process 0 จะทำการส่งค่า x ไปให้ Process 1 ซึ่งเจ้า Process 1 ก็จะรับค่ามาจาก Process 0 มาแล้วเก็บไว้ในค่า y (ดูโค้ดตัวอย่างประกอบด้วยนะ)

ตัว แปรที่ส่งจะต้องส่งในรูปของ "pointer" (คือส่งแบบ Parse by Reference ... มีสัญลักษณ์ [&] นำหน้าตัวแปร) และต้องบอกด้วยว่าตัวแปรที่เราส่งไปน่ะ มันเป็น int ขนาด 1 ตัว (จะมีขนาดมากกว่า 1 ตัวในกรณีที่เราส่งค่าแบบเป็น array ไงล่ะ)

สรุป ... ผลสุดท้ายค่าที่โปรเซสทั้งสองตัวเก็บก็จะเป็น

  • Process 0 เก็บค่าเป็น x = 100, y = 20
  • Process 1 เก็บค่าเป็น x = 10, y = 100

คำถามคือถ้าเราต้องการจะส่งข้อมูลจากโปรเซสหนึ่งไปให้โปรเซสอื่นอีกหลายๆ ตัวจะต้องทำยังไง

ก็ใช้ "Loop" ยังไงล่ะ!

for( i = 1; i<size; i++){ 
    MPI_Send( &x, 1, MPI_INT, i, 123, MPI_COMM_WORLD );
}

ตัวอย่าง เช่น ถ้าคราวนี้ Process 0 ต้องการจะส่งค่า x ไปให้โปรเซสอื่นทั้งหมดเลย แทนที่จะมาเรียก MPI_Send เองก็จัดการเขียนเป็นลูปซะเลย

แต่ เมื่อต้องเขียนแบบนี้ไปเรื่อยๆ เขาก็เริ่มเห็นว่ามันน่าจะมีคำสั่งอะไรที่มันดีกว่า Send-Receive สิน่า แบบสั่งครั้งเดียวได้เลย ไม่ต้องมานั่งลูปเอง ... ใช่แล้ว มันเลยเกิดชุดคำสั่งที่เรียกว่า "Collective Communication" เกิดขึ้นมา (ซึ่งเอาไว้คราวหน้าค่อยมาพูดต่อละกัน ฮา)

554 Total Views 3 Views Today
Ta

Ta

สิ่งมีชีวิตตัวอ้วนๆ กลมๆ เคลื่อนที่ไปไหนโดยการกลิ้ง .. ถนัดการดำรงชีวิตโดยไม่โดนแสงแดด
ปัจจุบันเป็น Senior Software Engineer อยู่ที่ Centrillion Technology
งานอดิเรกคือ เขียนโปรแกรม อ่านหนังสือ เขียนบทความ วาดรูป และ เล่นแบดมินตัน

ใส่ความเห็น

อีเมลของคุณจะไม่แสดงให้คนอื่นเห็น ช่องที่ต้องการถูกทำเครื่องหมาย *