Một câu đủ dùng (Rob Pike / Go talks — ý được nhắc lại rất nhiều nơi):
Concurrency is about dealing with lots of things at once.
Parallelism is about doing lots of things at once.
- Dealing with — bạn đang gánh nhiều việc cùng một giai đoạn: mở dở, chờ, xen kẽ, xếp hàng, không bỏ rơi. Chưa chắc hai việc đang chạy instruction cùng một nanosecond.
- Doing — nhiều việc thật sự được thực thi cùng lúc: nhiều core, nhiều máy, nhiều worker vật lý.
Tiếng Việt gần: concurrency = xoay xở nhiều việc một lúc; parallel = làm nhiều việc một lúc.
Demo animation (1 core xoay xở vs 2 core cùng làm): concurrency vs parallel.
Dealing with — concurrent
Nhân viên support 1 người, 20 ticket mở: vừa reply A, vừa chờ khách B, vừa đọc log C. Cùng lúc đang deal nhiều ticket — không phải 20 người gõ phím cùng lúc.
Trong code: event loop, async/await, goroutine chờ I/O, connection pool đầy request dang dở…
// Đang “deal” 100 fetch — phần lớn thời gian là chờ mạng
await Promise.all(urls.map((u) => fetch(u)))
// 1 thread JS: dealing with lots of I/O
// không phải 100 core đang parse body cùng lúc
Concurrency là cách tổ chức để hệ thống chịu được nhiều việc in-flight: ai chờ cái gì, khi nào resume, không block hết cả nhà vì một lời gọi chậm. Thường đi với non-blocking.
Có thể concurrent trên một core: OS/runtime xen kẽ. Bạn vẫn “deal with lots of things” — chỉ là lần lượt trong từng lát thời gian rất ngắn, hoặc chồng chờ I/O.
Doing — parallel
Hai (hay N) người support cùng lúc, mỗi người gõ một ticket — doing nhiều việc at once trên nhiều “bộ não”.
Trong code: multi-thread/process CPU, shard job trên nhiều pod, GPU hàng nghìn lane…
// N process cùng compress — doing trên N core (nếu có)
await processPool.map(chunks, compress)
Parallel cần nhiều đơn vị thực thi cùng lúc. Thêm replica K8s, bật worker pool, chia data / task — đều là tăng “doing”.
Cùng lúc trên giấy vs cùng lúc trên silicon
Dealing with (concurrent)
timeline logic: A, B, C đều “đang mở”
silicon: có thể chỉ 1 core; A chờ DB thì B chạy
Doing (parallel)
timeline logic: A và B đều “đang compute”
silicon: 2 core cùng fetch/decode instruction
Người ta hay nhầm vì cả hai đều nói “at once”. Khác ở at once kiểu nào: nhiều việc trong tay (deal) vs nhiều việc đang chạy (do).
Một hình số
3 request × (CPU 10ms + I/O 100ms + CPU 10ms)
Chỉ dealing, 1 core, non-block:
3 request “mở” chồng I/O → wall ~ 100 + 60 ms
dealing with 3; doing CPU vẫn 1 luồng
Doing thêm 2 core (+ vẫn deal I/O):
hai đoạn CPU có thể cháy cùng wall-clock
dealing + doing — wall ngắn hơn nữa
Khi nào cần cái nào
- Nhiều chờ (DB, HTTP, disk): cần dealing with giỏi — concurrent + non-block — kẻo một thread/process chỉ gánh được ít request.
- Nhiều tính (hash, encode, aggregate): cần doing trên nhiều core — parallel; chỉ async không rút wall CPU.
- Hệ thật: thường cả hai — nhiều instance doing song song, mỗi instance dealing with hàng nghìn connection.
Runtime (một dòng mỗi cái)
- Node / asyncio: mạnh dealing with I/O; doing CPU → worker/process khác.
- Go: goroutine = dealing with rẻ; scheduler map lên nhiều OS thread = doing khi có multi-core + work.
- K8s N pod: doing ở mức máy; trong mỗi pod vẫn phải dealing with request.
Đọc tiếp
- Blocking vs non-blocking — chờ mà vẫn deal được việc khác, hay bị kẹt.
- Coroutine — suspend/resume: unit “deal” trên event loop / runtime.
- Data vs task parallelism — khi đã doing, cắt theo data hay theo task.
Một câu để nhớ
Concurrency = dealing with lots of things at once.
Parallelism = doing lots of things at once.
Deal = nhiều việc dang dở, có tổ chức. Do = nhiều việc đang chạy thật trên nhiều unit. Nhầm “at once” là tối ưu sai chỗ: bọc async cho bài CPU, hoặc thêm core cho chỗ chỉ cần biết chờ cho khéo.