Concurrency vs parallel:

Concurrency = dealing with lots of things at once
Parallelism = doing lots of things at once

Khi bạn đã quyết doing — chạy thật trên nhiều core / worker / máy — vẫn còn hỏi: cắt “lots of things” theo chiều nào?

  • Data parallelism — cùng một phép, áp lên nhiều phần dữ liệu cùng lúc. Doing the same kind of work on lots of data at once.
  • Task parallelism — nhiều việc khác nhau (hoặc stage khác nhau) chạy cùng lúc. Doing different kinds of work at once.

Cả hai đều nằm phía doing (parallel), không phải định nghĩa concurrency. Concurrency có thể deal nhiều task I/O trên 1 core mà chưa data-parallel CPU.

Demo: map trên mảng vs 3 task khác loại.

Data parallelism — one function × many pieces

out[i] = f(in[i])   // mọi i, ideally cùng lúc trên N worker

map(chunks, compress)
GPU thread / SIMD
Spark map, Go shard slice + cùng closure
ProcessPool.map(pages, render)

“Lots of things” ở đây là lots of data items. Workload đồng nhất → dễ scale theo kích thước input; hay dính straggler (chunk chậm nhất), marshal qua process, bão memory bandwidth.

mapPool trên list cùng loại work: cơ chế schedule; data-parallel là cách bổ bài “chia data cho nhiều do-er”.

Task parallelism — different jobs at once

// ba việc khác nhau — doing (hoặc dealing) cùng lúc
parallel {
  fetchUser()
  resizeImage()
  sendEmail()
}

// pipeline: mỗi stage một “loại việc”
read → parse → enrich → write

“Lots of things” là lots of tasks / kinds of work. Thời lượng lệch, phụ thuộc DAG: chỉ song song nhánh độc lập. Fan-out service, CI steps, media pipeline…

Lưu ý: await Promise.all([getUser(), getOrders()]) trên 1 thread Node thường là dealing with nhiều I/O (concurrency), chưa chắc doing CPU song song. Cùng hình task-parallel logic; parallel silicon chỉ khi runtime/phần cứng chạy thật cùng lúc (multi-core worker, nhiều process…).

Deal vs do — đừng dán nhầm nhãn

Data-parallel CPU trên 1 thread async
  → không rút wall: bạn chỉ deal (xen kẽ), không do trên nhiều core

Task-parallel I/O non-block trên 1 loop
  → dealing with lots of tasks — đúng concurrency
  → parallel chỉ khi có thêm unit thực thi

Task-parallel 3 process encode/transcode
  → doing different work at once — parallel thật

Non-blocking giúp deal nhiều task I/O. Data/task parallelism mô tả bổ work thế nào khi (hoặc trước khi) map lên nhiều do-er.

So một nhịp

  • Cắt theo đâu? Data → phần tử/chunk. Task → hàm/stage/job.
  • Đồng nhất? Data: cùng f. Task: heterogeneous OK.
  • Hardware: GPU/SIMD ~ data-parallel. Thread pool / job graph ~ task-parallel linh hoạt.
  • Lỗi: data → retry chunk; task → retry node trên DAG (idempotent từng task).

Ví dụ stack (doing / dealing)

  • Go: shard slice + worker (data doing); errgroup 3 hàm (task — I/O deal hoặc CPU do tùy body).
  • Python: ProcessPoolExecutor.map (data doing, tránh GIL); asyncio.gather (task dealing I/O).
  • Node: gather HTTP (task deal); worker_threads chia buffer (data do).
  • K8s: Job N partition (data doing ở mức cluster); nhiều service khác vai trò (task ở mức hệ thống).

Bẫy

  • Data-parallel nhưng chunk phụ thuộc + lock chung → doing kém vì contention.
  • Task fan-out 50 service không budget / breaker → p99 nổ (deal/do quá nhiều dependency một lúc).
  • Pipeline: stage chậm = throughput — cần backpressure giữa stage.

Một câu để nhớ

Parallel = doing lots of things at once.
Data-parallel = doing the same work on lots of data at once.
Task-parallel = doing different works at once.

Concurrency vẫn là dealing with lots of things — tổ chức nhiều việc dang dở, chưa đủ nghĩa nhiều core đang chạy. Bổ data hay task chỉ rõ doing cái gì song song; phần cứng và runtime quyết có “at once” thật hay không.