Concurrency Parallelism Python Go Programming

Concurrency Parallelism Python Go

📅 2026-02-09 | โดย อ.บอม กิตติทัศน์ เจริญพนาสิทธิ์ — SiamCafe.net Since 1997

Concurrency, Parallelism, Python, Go คืออะไร / ทำไมถึงสำคัญ

น้องๆ เคยสงสัยไหมว่าทำไมโปรแกรมบางทีมันทำงานช้าจัง? หรือทำไมบางแอปถึงทำหลายอย่างพร้อมๆ กันได้? นั่นแหละคือเรื่องของ Concurrency กับ Parallelism ที่เราจะมาคุยกันวันนี้ มันสำคัญมากๆ เพราะมันช่วยให้โปรแกรมเราทำงานได้เร็วขึ้น และจัดการงานต่างๆ ได้ดีขึ้น โดยเฉพาะในยุคที่ CPU มีหลาย core และเราต้องจัดการงานพร้อมๆ กันเยอะๆ

Concurrency คือการจัดการงานหลายอย่าง "เหมือน" ทำพร้อมกัน แต่จริงๆ แล้วสลับกันทำไปเรื่อยๆ เหมือนเราเป็น Supermarket cashier ที่สลับกันคิดเงินลูกค้าแต่ละคนไปเรื่อยๆ ส่วน Parallelism คือการทำงานหลายอย่าง "พร้อมกันจริงๆ" โดยใช้ CPU หลาย core เหมือนมี cashier หลายคนคิดเงินลูกค้าพร้อมๆ กันเลย

Python กับ Go เป็นภาษาที่ support ทั้ง Concurrency และ Parallelism แต่ด้วยวิธีที่ต่างกัน Python จะเน้น Concurrency มากกว่า เพราะติดเรื่อง Global Interpreter Lock (GIL) ส่วน Go ออกแบบมาให้ Parallelism ทำงานได้ดีกว่า

พื้นฐานที่ต้องรู้

ก่อนจะไปลงมือเขียน code เราต้องเข้าใจ concept พื้นฐานพวกนี้ก่อนนะ

Thread vs Process

Process คือโปรแกรมที่กำลังทำงานอยู่ แต่ละ process จะมี memory space เป็นของตัวเอง ส่วน Thread คือหน่วยย่อยของการทำงานใน process หนึ่งๆ process หนึ่งอาจจะมีหลาย thread ก็ได้ Thread จะ share memory space กันได้ ทำให้สื่อสารกันง่าย แต่ก็ต้องระวังเรื่อง race condition ด้วย

สมัยผมทำร้านเน็ต ผมเคยเจอเคสที่โปรแกรม server crash เพราะหลาย thread เข้าไปแก้ข้อมูลใน memory พร้อมๆ กัน ทำให้ข้อมูลมันเพี้ยนไปหมด ต้องมานั่ง debug กันหัวแตกเลย

Race Condition & Mutex

Race condition คือสถานการณ์ที่ผลลัพธ์ของการทำงานขึ้นอยู่กับลำดับการทำงานของ thread หลายๆ ตัว ถ้าลำดับมันเปลี่ยน ผลลัพธ์ก็เปลี่ยนไปด้วย ซึ่งส่วนใหญ่จะไม่ใช่สิ่งที่เราต้องการ Mutex (Mutual Exclusion) เป็นเครื่องมือที่ใช้ป้องกัน race condition โดยการ lock resource ไม่ให้ thread อื่นเข้ามายุ่ง จนกว่า thread ที่ lock จะปล่อย

คิดภาพง่ายๆ เหมือนห้องน้ำสาธารณะ มีคนเข้าไปใช้แล้วล็อคประตู คนอื่นก็ต้องรอจนกว่าคนข้างในจะออกมาปลดล็อคก่อนถึงจะเข้าไปได้

วิธีใช้งาน / เริ่มต้นยังไง

มาดูวิธีใช้ Concurrency และ Parallelism ใน Python และ Go กัน เริ่มจาก Python ก่อนนะ

ขั้นตอนปฏิบัติจริง (Python)

Threading ใน Python

Python มี module threading ที่ช่วยให้เราสร้างและจัดการ thread ได้ง่ายๆ ลองดูตัวอย่างนี้


import threading
import time

def task(name):
    print(f"Thread {name}: starting")
    time.sleep(2)  # Simulate some work
    print(f"Thread {name}: finishing")

threads = []
for i in range(3):
    t = threading.Thread(target=task, args=(i,))
    threads.append(t)
    t.start()

for t in threads:
    t.join()  # Wait for all threads to complete

print("All threads finished")

code นี้สร้าง 3 thread แต่ละ thread จะ run function task ซึ่งจะพิมพ์ข้อความ แล้ว sleep ไป 2 วินาที จากนั้นก็พิมพ์ข้อความอีกที สังเกตว่า thread ทั้ง 3 ตัวจะทำงาน "เหมือน" พร้อมกัน แต่จริงๆ แล้ว Python จะสลับกัน run thread แต่ละตัวไปเรื่อยๆ เพราะติด GIL

Asynchronous Programming (asyncio) ใน Python

asyncio เป็น library ที่ช่วยให้เราเขียน asynchronous code ใน Python ได้ง่ายขึ้น Asynchronous code จะใช้ event loop ในการจัดการ task หลายๆ อย่าง ทำให้โปรแกรมเราไม่ block และสามารถทำงานอื่นๆ ไปพร้อมๆ กันได้


import asyncio
import time

async def task(name):
    print(f"Task {name}: starting")
    await asyncio.sleep(2)  # Simulate some work
    print(f"Task {name}: finishing")

async def main():
    tasks = [task(i) for i in range(3)]
    await asyncio.gather(*tasks)  # Run all tasks concurrently

if __name__ == "__main__":
    asyncio.run(main())

code นี้คล้ายกับตัวอย่าง threading แต่ใช้ async และ await แทน asyncio.sleep จะไม่ block event loop ทำให้ task อื่นๆ สามารถทำงานได้ในขณะที่รอ sleep เสร็จ

ขั้นตอนปฏิบัติจริง (Go)

Goroutines ใน Go

Go มี concept ที่เรียกว่า Goroutine ซึ่งคล้ายกับ thread แต่ lightweight กว่ามากๆ เราสามารถสร้าง Goroutine ได้เยอะๆ โดยไม่เปลือง resource มากนัก


package main

import (
	"fmt"
	"time"
)

func task(name int) {
	fmt.Printf("Goroutine %d: starting\n", name)
	time.Sleep(2 * time.Second) // Simulate some work
	fmt.Printf("Goroutine %d: finishing\n", name)
}

func main() {
	for i := 0; i < 3; i++ {
		go task(i) // Start a new goroutine
	}

	time.Sleep(3 * time.Second) // Wait for goroutines to complete (not ideal)
	fmt.Println("All goroutines finished")
}

code นี้สร้าง 3 Goroutine แต่ละ Goroutine จะ run function task ซึ่งจะพิมพ์ข้อความ แล้ว sleep ไป 2 วินาที จากนั้นก็พิมพ์ข้อความอีกที สังเกตว่า Goroutine ทั้ง 3 ตัวจะทำงานพร้อมกันจริงๆ เพราะ Go ออกแบบมาให้ Parallelism ทำงานได้ดี

สมัยผมทำ server ด้วย Go ผมใช้ Goroutine เยอะมากๆ เพราะมันจัดการง่ายและ performance ดีกว่า threading ใน Python เยอะเลย

Channels ใน Go

Channel เป็นวิธีที่ Go ใช้ในการสื่อสารระหว่าง Goroutine มันเป็น type-safe queue ที่ช่วยให้เราส่งและรับข้อมูลระหว่าง Goroutine ได้อย่างปลอดภัย


package main

import (
	"fmt"
	"time"
)

func task(name int, ch chan string) {
	fmt.Printf("Goroutine %d: starting\n", name)
	time.Sleep(2 * time.Second) // Simulate some work
	fmt.Printf("Goroutine %d: finishing\n", name)
	ch <- fmt.Sprintf("Task %d completed", name)
}

func main() {
	ch := make(chan string, 3) // Create a channel with buffer size 3

	for i := 0; i < 3; i++ {
		go task(i, ch) // Start a new goroutine
	}

	for i := 0; i < 3; i++ {
		result := <-ch // Receive from the channel
		fmt.Println(result)
	}

	fmt.Println("All goroutines finished")
}

code นี้ใช้ channel ในการส่ง message จาก Goroutine กลับมาที่ main Goroutine เพื่อบอกว่า task เสร็จแล้ว

เปรียบเทียบกับทางเลือกอื่น

นอกจาก threading, asyncio และ Goroutine แล้ว ยังมีทางเลือกอื่นๆ อีกมากมายในการจัดการ Concurrency และ Parallelism แต่ละทางเลือกก็มีข้อดีข้อเสียต่างกันไป

เทคนิค ภาษา ข้อดี ข้อเสีย
Threading Python, Java, C++ ใช้งานง่าย ติด GIL (Python), overhead สูง
Asyncio Python Efficient, non-blocking เขียนยากกว่า threading
Goroutines Go Lightweight, efficient, built-in support ต้องเรียนรู้ syntax ใหม่
Multiprocessing Python Bypass GIL, true parallelism Overhead สูงกว่า threading, สื่อสารระหว่าง process ยาก

ถ้างานของเราเป็น I/O bound (เช่น อ่าน/เขียน file หรือ network) asyncio หรือ Goroutine จะเป็นทางเลือกที่ดีกว่า เพราะมันจะไม่ block โปรแกรมของเรา แต่ถ้านานของเราเป็น CPU bound (เช่น คำนวณเลขเยอะๆ) multiprocessing จะเป็นทางเลือกที่ดีกว่า เพราะมันจะใช้ CPU หลาย core ได้อย่างเต็มที่ SiamCafe Blog มีบทความเกี่ยวกับเรื่องนี้เยอะเลย ลองไปอ่านดูได้

สุดท้ายนี้ การเลือกใช้เทคนิคไหน ก็ขึ้นอยู่กับ requirement ของโปรเจกต์เรา และความถนัดของแต่ละคน อย่ากลัวที่จะลองผิดลองถูก และเรียนรู้จากประสบการณ์จริงนะ SiamCafe Blog เองก็เป็นที่ที่ผมแชร์ประสบการณ์ต่างๆ ที่ได้จากการทำงานจริง หวังว่าน้องๆ จะได้ประโยชน์จากบทความนี้นะครับ

🎬 วิดีโอแนะนำ

ดูวิดีโอเพิ่มเติมเกี่ยวกับConcurrency Parallelism Python:

Best Practices / เคล็ดลับจากประสบการณ์

น้องๆ หลายคนถามพี่ว่า "พี่บอม concurrency กับ parallelism นี่มันยากจัง มีเคล็ดลับอะไรบ้างครับ?" อ่ะ เดี๋ยวพี่เล่าให้ฟังจากประสบการณ์ตรงสมัยทำร้านเน็ต SiamCafe เลย

ตอนนั้นเน็ตเราช้ามาก (56k modem อ่ะคิดดู) แต่ลูกค้าอยากเล่นเกมออนไลน์พร้อมกันหลายเครื่อง พี่เลยต้องหาวิธีจัดการ resource ให้ดีที่สุด concurrency กับ parallelism เลยเข้ามามีบทบาท พี่ลองผิดลองถูกมาเยอะ เจ็บมาเยอะ เลยพอมีเคล็ดลับมาฝากกัน

3-4 เทคนิคที่ใช้ได้จริง

1. เข้าใจปัญหา ก่อนลงมือเขียน code

น้องต้องเข้าใจก่อนว่า ปัญหาที่น้องเจออยู่จริงๆ คืออะไร ต้องการให้โปรแกรมทำงานเร็วขึ้น? หรือต้องการให้มันตอบสนองได้ดีขึ้น? เพราะ concurrency กับ parallelism มันแก้ปัญหาคนละแบบ ถ้าเลือกผิดชีวิตเปลี่ยนเลยนะ

สมัยพี่ทำร้านเน็ต พี่ต้องทำให้เครื่อง server รับ request จาก client ได้เยอะๆ พร้อมๆ กัน เลยเน้น concurrency มากกว่า เพราะ CPU มันไม่ได้แรงมาก แต่ต้องจัดการงานหลายอย่าง

2. เลือกภาษาให้เหมาะสม

Python นี่เขียนง่าย อ่านง่าย แต่เรื่อง concurrency อาจจะไม่ได้เปรียบเทียบเท่า Go เพราะติดเรื่อง Global Interpreter Lock (GIL) Go เกิดมาเพื่อ concurrency โดยเฉพาะ Goroutine นี่เบาหวิวมาก

ถ้างานน้องเน้น I/O-bound (รออ่านเขียนข้อมูลจาก disk หรือ network) Python อาจจะตอบโจทย์กว่า แต่ถ้าน้องต้องการ CPU-bound (คำนวณหนักๆ) Go น่าจะดีกว่า

# Python example (asyncio)
import asyncio

async def my_task(name):
    print(f"Task {name}: Starting")
    await asyncio.sleep(1)
    print(f"Task {name}: Finished")

async def main():
    tasks = [my_task("A"), my_task("B")]
    await asyncio.gather(*tasks)

if __name__ == "__main__":
    asyncio.run(main())

3. ใช้ Thread Pool ให้เป็น

สร้าง thread เยอะเกินไปก็เปลือง resource เหมือนกัน Thread Pool ช่วยให้น้องจัดการ thread ได้อย่างมีประสิทธิภาพ reuse thread ได้ ไม่ต้องสร้างใหม่ทุกครั้ง

พี่เคยเจอเคสที่ client ส่ง request มาถี่ๆ แล้ว server สร้าง thread ใหม่ทุก request ผลคือ server แฮงค์ไปเลย เพราะ resource ไม่พอ Thread Pool ช่วยแก้ปัญหานี้ได้ดีมาก

// Go example (using goroutines and waitgroups)
package main

import (
	"fmt"
	"sync"
	"time"
)

func worker(id int, wg *sync.WaitGroup) {
	defer wg.Done()
	fmt.Printf("Worker %d starting\n", id)
	time.Sleep(time.Second)
	fmt.Printf("Worker %d done\n", id)
}

func main() {
	var wg sync.WaitGroup
	for i := 1; i <= 3; i++ {
		wg.Add(1)
		go worker(i, &wg)
	}
	wg.Wait()
}

4. Monitoring and Profiling สำคัญมาก

อย่าคิดว่า code ที่น้องเขียนมันจะ performant ตั้งแต่แรก Test ให้เยอะ monitor ให้ดี profile ให้ละเอียด จะได้รู้ว่า bottleneck มันอยู่ตรงไหน แล้วค่อยแก้

สมัยพี่ทำร้านเน็ต พี่ใช้ tool หลายตัวในการ monitor CPU usage, memory usage, network traffic เพื่อหาจุดที่ต้องปรับปรุง

FAQ คำถามที่พบบ่อย

ทำไม Python ถึงมี GIL? มันทำให้ concurrency แย่ลงหรือเปล่า?

GIL มีไว้เพื่อป้องกัน data race ใน CPython (implementation หลักของ Python) มันทำให้ thread สามารถ access object ได้ทีละ thread เท่านั้น ข้อดีคือเขียน code ง่ายขึ้น ข้อเสียคือ performance อาจจะไม่ดีเท่าที่ควรใน CPU-bound task แต่ถ้าเป็น I/O-bound task GIL ไม่ค่อยมีผลเท่าไหร่

Goroutine ใน Go มันต่างจาก thread ยังไง?

Goroutine เบากว่า thread มาก เพราะมันจัดการโดย Go runtime ไม่ใช่ OS Goroutine ใช้ memory น้อยกว่า สร้างเร็วกว่า switch เร็วกว่า ทำให้ Go สามารถ run goroutine ได้เป็นจำนวนมาก

ควรใช้ Channel ใน Go เมื่อไหร่?

Channel ใช้สำหรับ communicate ระหว่าง goroutine มันช่วยให้เรา synchronize ข้อมูลและป้องกัน data race ได้ ใช้เมื่อ goroutine ต้องส่งข้อมูลให้กัน หรือต้องรอให้ goroutine อื่นทำงานเสร็จก่อน

สรุป

Concurrency กับ parallelism เป็นเรื่องที่ซับซ้อน แต่ถ้าเข้าใจหลักการ และเลือกใช้เครื่องมือให้เหมาะสม น้องๆ ก็จะสามารถเขียนโปรแกรมที่มีประสิทธิภาพได้

อย่าลืมว่า practice makes perfect ลองทำโจทย์ ลองเขียน code เยอะๆ แล้วน้องจะเก่งขึ้นเอง SiamCafe Blog มีบทความดีๆ อีกเยอะ ลองเข้าไปอ่านดูนะ

ถ้าสนใจเรื่อง forex ลองดู iCafeForex ได้นะ อันนี้พี่ไม่ได้ทำเองนะจ๊ะ