พยายามใช้ cpu ให้ครบทุก core

ผมไม่ค่อยรู้เรื่อง parallel computing เท่าไหร่ก็จะเขียนเล่าไปเรื่อยเปื่อย แต่มิวายก็ต้องมายุ่งบ้างเพราะ CPU ชักจะเริ่มมีหลาย core

มีหลายกรณีนี่เลยที่ง่าย ๆ

  1. เปิด app ขึ้นมาหลาย ๆ ตัวแล้วให้มันงานพร้อมกัน แต่เอาจริง ๆ อันนี้ 2 core ส่วนมากก็พอแล้ว
  2. เขียนเว็บแบบธรรมดา ๆ นี่เองพอมีคนเข้ามาดูหลาย ๆ คนมันก็ใช้หลาย core เอง
  3. เวลาเขียน script แบบที่ทำงานกับหลาย ๆ ไฟล์แยกกัน แต่ก่อนใช้ find | xargs ก็เปลี่ยนไปใช้ GNU Parallel แทน เช่น เวลาแปลงรูปด้วย ImageMagick แล้วสั่ง convert พร้อม ๆ กัน

เวลาทำแบบข้างบนได้ส่วนมากก็พึ่งพาความสามารถของ OS เช่น GNU/Linux หรือ Windows ที่มันทำได้หลาย ๆ งานพร้อมกันอยู่แล้ว รวมถึงกรณีของเว็บก็พึ่ง web server ด้วย บางทีก็พึ่ง Database ด้วย

จากตัวอย่างข้างบนเราก็เขียนโปรแกรมธรรมดา ๆ แบบเดิม ๆ มันก็ใช้หลาย core ได้ มากไปกว่านั้นดูเหมือนกว่างานของ programmer ส่วนมากก็จะเข้าข่ายกรณีนี้ด้วย คือไม่ต้องทำอะไรพิเศษ

พอมาดูเครื่องมือเรื่อง word embedding และ artificial neural network เช่นพวก PyTorch Tensorflow แค่บอกประมาณว่าเอา tensor มาทำอะไรกัน เดี๋ยว framework ก็จะไปจัดให้ใช้หลาย core ให้เอง หรือแม้แต่ใช้ GPU ก็ได้

แต่ก็มีบางทีมีบางทีที่โปรแกรมที่เขียนขึ้นมาเองมันช้าแล้วอยากจะใช้หลาย ๆ core บ้าง ที่แรกที่ผมนึกออกเลยก็คือใช้ pmap แทน map; map นี้ถ้าใครเขียนโปรแกรมแบบ functional programming อยู่แล้วก็คงใช้บ่อย หลาย ๆ กรณีก็เอามาใช้แทน for-loop พอเปลี่ยนจาก map เป็น pmap โปรแกรมมันใช้หลาย core เองเลยแก้แค่นี้เลย

อีกท่าคือใช้ thread pool ท่านี้ก็มักจะใช้ library หรือจะเขียนเองก็ตามแต่ มาสร้าง thread ไว้ก่อน ปกติแล้วก็เอาเท่าจำนวน core เลย หรือถ้าใช้ hyper thread ก็เท่าจำนวน thread ที่ cpu นั้นรับได้พร้อมกัน แล้วก็เอางานไปเข้า queue ไว้แล้ว thread pool มันจะดึงงานใน queue ไปแจกใส่ thread ที่ว่างงานอยู่

ส่วนมากข้อมูลระหว่าง thread ถ้าต้องส่งไปมาช่วงนี้ผมก็มักจะใช้ channel แบบที่ใครเขียน Go ก็คงได้ใช้กันบ่อย ๆ ผมได้ลองเล่นครั้งแรกก็ตอนเขียน Go ราว ๆ ปี 2013 หลายท่านบอกมาว่าจริง ๆ มีมาตั้งแต่ Limbo ตอนนี้ก็ใช้ได้ทั้งใน Rust และ Clojure ด้วย ภาษาอื่น ๆ ก็คงจะมีเหมือนกันแต่ผมไม่เคยเขียน

ไม่ใช่ข้อมูลทุกอย่างที่จะเหมาะกับการส่งไปใน channel บาง อีกท่าหนึ่งคือ shared memory มันควรจะเร็วกว่าส่งไปใน channel ปกติท่านี้มันก็ควรจะง่าย ๆ ถ้าอ่านข้อมูลอย่างเดียวไม่เขียน พอเขียนก็ชักเป็นเรื่อง ก็ต้องมีเรื่อง mutex lock หรืออื่น ๆ เข้ามา ใน Rust เห็นว่ามี atomic type ด้วย เข้าใจว่าเอามาจาก C++ อีกที
ผมมองว่าทั้งข้อดีและความวุ่นวายต่าง ๆ ของ Rust มันมาอยู่ที่ตอนเขียน parallel แบบ shared memory นี่เอง type system มัน check ได้เลยว่าต้อง lock ตัวแปรไหนบ้าง จริง ๆ พวก mutex lock นี้จะใช้ Go หรือ C เขียนเอาก็ได้ แต่ว่าจะ lock ตรงไหนก็ขึ้นกับ programmer ทาง compiler ไม่ค่อยได้ช่วยอะไรมาก แต่ประมาณว่าแค่เขียน linked list ให้แก้ link ได้ก็ปวดหัวได้

 

Advertisements
This เรื่อง was posted in ไม่มีหมวดหมู่. Bookmark the permalink.

ใส่ความเห็น

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / เปลี่ยนแปลง )

Twitter picture

You are commenting using your Twitter account. Log Out / เปลี่ยนแปลง )

Facebook photo

You are commenting using your Facebook account. Log Out / เปลี่ยนแปลง )

Google+ photo

You are commenting using your Google+ account. Log Out / เปลี่ยนแปลง )

Connecting to %s