Đồng thời & song song: đo tận nơi

Sê-ri 45 bài đo thật về lập trình đồng thời và song song bằng C/pthreads/atomic trong container: chi phí luồng, khóa, atomic, false sharing, scaling — mỗi bài một phép đo, một đo hớ, một sơ đồ.

45/45 phần đã đăng Giải thuật
1 Tạo một luồng tốn 47µs, fork một tiến trình chỉ 82µs: cả hai niềm tin thường gặp đều sai Tưởng tạo luồng gần như miễn phí, còn fork đắt gấp trăm lần vì phải nhân đôi cả bộ nhớ? Tôi đo: tạo+join một luồng rỗng mất ~47µs (không hề miễn phí), fork+waitpid ~82µs — fork chỉ 1,8 lần thread nhờ copy-on-write. Cả hai đều tốn hàng chục micro giây, và đó là lý do có thread pool. 03/09/2026 · 9 phút đọc 2 Đổi qua lại giữa hai tiến trình không hề đắt hơn giữa hai luồng — sách đã lỗi thời Tưởng chuyển ngữ cảnh gần như tức thì, và chuyển giữa tiến trình đắt hơn hẳn giữa luồng vì phải xả TLB? Tôi đo bằng ping-pong qua pipe: mỗi lần chuyển ~8,5µs (hàng nghìn chu kỳ, không tức thì), và tiến trình bằng luồng (~1,0x) nhờ TLB gắn nhãn ASID. Một 'sự thật' sách giáo khoa đã lỗi thời vì phần cứng tiến hóa. 03/09/2026 · 9 phút đọc 3 Mutex không tranh chấp chỉ tốn 3,3ns: cái đắt của khóa không nằm ở nơi bạn tưởng Tưởng khóa luôn đắt, hoặc mutex bị giành thì mỗi thao tác tốn ~8,5µs vì luồng phải ngủ? Tôi đo tinh tế hơn: không tranh chấp chỉ 3,3ns (futex, không vào nhân), tranh chấp với vùng tới hạn ngắn chỉ ~25ns (spin + cache nảy), chỉ vùng tới hạn dài mới thật sự ngủ. Cái đắt là tranh chấp nhân độ dài vùng tới hạn, không phải việc khóa. 03/09/2026 · 9 phút đọc 4 Atomic 'lock-free' vẫn chậm 10 lần khi đông, và vòng CAS còn thua cả mutex Tưởng atomic miễn phí, lock-free nên không bị tranh chấp, luôn nhanh hơn mutex nhiều lần? Tôi đo cả ba đều lệch: atomic không tranh chấp chỉ ~1,6ns (rẻ hơn mutex 2 lần, cùng bậc), fetch_add tranh chấp vẫn chậm 10 lần vì cache nảy, và vòng CAS 8 luồng chậm hơn cả mutex vì phải thử lại. Lock-free không phải contention-free. 03/09/2026 · 9 phút đọc 5 Mỗi luồng ghi biến riêng, không chia sẻ gì — vẫn chậm gấp đôi: bí ẩn false sharing Tưởng hai biến khác nhau, mỗi luồng ghi biến của riêng mình thì không thể ảnh hưởng nhau? Tôi đo: chúng làm nhau chậm 2,05 lần ở 8 luồng vì tình cờ nằm chung một dòng cache 64 byte — false sharing. Căn lề mỗi biến sang một dòng riêng thì nhanh gấp đôi, dù logic không đổi một chữ. Bug hiệu năng vô hình trong mã nguồn. 03/09/2026 · 9 phút đọc 6 16 luồng chạy chậm hơn 1 luồng 16 lần: khi thêm luồng làm chương trình tệ đi Tưởng thêm luồng luôn nhanh hơn và song song scale tuyến tính? Tôi đo hai workload trên cùng một máy: loại độc lập scale tới ~số lõi (4,86× ở 16 luồng), còn loại cùng ghi một biến scale ÂM — 16 luồng chỉ bằng 6% một luồng. Khác biệt duy nhất là có chia sẻ ghi hay không. Song song không tự động nhanh. 03/09/2026 · 9 phút đọc 7 Spinlock nhanh hơn mutex 1,7 lần — rồi chậm hơn 36 lần khi đông luồng Tưởng spinlock luôn nhanh hơn mutex vì không vào nhân? Tôi đo: ở tranh chấp thấp và ít luồng, spinlock nhanh 1,7 lần; nhưng đông luồng hoặc vượt số lõi thì spinlock đốt CPU quay vô ích và chậm hơn mutex 7 đến 36 lần, trong khi mutex gần như phẳng. Không có cái luôn thắng — chọn theo hoàn cảnh, không theo khẩu hiệu. 03/09/2026 · 9 phút đọc 8 Read-write lock với 8 luồng toàn đọc lại chậm hơn mutex 5,9 lần — trừ khi mỗi lần đọc đủ dài Tưởng cứ đọc nhiều thì rwlock luôn nhanh hơn mutex? Tôi đo: với vùng tới hạn đọc cực ngắn, rwlock chậm hơn mutex 5,9 lần vì bộ đếm đọc là một ghi chung bị cache nảy; chỉ khi mỗi lần đọc đủ dài rwlock mới thắng 6,3 lần nhờ đọc thật sự song song. Điểm lật nằm ở độ dài đọc, không phải ở đọc-nhiều-hay-ít. 03/09/2026 · 9 phút đọc 9 Lock-free nhanh gấp 3 lần mutex — cho tới khi 8 producer khiến nó thua ngược Tưởng lock-free luôn nhanh hơn có khóa nên cứ bỏ mutex đi? Tôi đo: hàng đợi SPSC lock-free nhanh hơn mutex 3 lần vì hai bên ghi hai chỉ số riêng không tranh; nhưng nhiều producer cùng đẩy vào một hàng đợi thì ở 8 producer lock-free lại thua mutex, vì đụng đúng bức tường cache. Lock-free nhanh khi không có ghi chung, và cái giá là code khó viết đúng. 03/09/2026 · 9 phút đọc 10 Hạ seq_cst xuống relaxed để 'đi nhanh' trên ARM: đo ra tiết kiệm 1%, đổi lấy một lớp bug Tưởng seq_cst đắt hơn relaxed nhiều nên nên hạ xuống cho nhanh? Tôi đọc assembly và bấm giờ trên ARMv8: ba mức sinh lệnh khác nhau nhưng thời gian chênh ~1% vì ARM có sẵn ldar/stlr/ldaddal, không cần rào dmb nặng. Chọn ordering cho đúng ngữ nghĩa, không phải tốc độ — seq_cst mặc định gần như miễn phí. 03/09/2026 · 9 phút đọc 11 CPU sắp lại thứ tự bộ nhớ thật — 11 lần trong 60 triệu vòng, hiếm tới mức test không bao giờ bắt được Tưởng CPU luôn chạy theo thứ tự mình viết, còn reorder bộ nhớ chỉ là lý thuyết trong sách? Tôi đo litmus store-buffer trên ARM: reorder xảy ra thật (11 ca trong 60 triệu vòng), rào dmb ish dập được về 0. Nhưng nó hiếm tới ~1 trên 5,5 triệu vòng — nên code sai vẫn qua sạch mọi test rồi nổ ở production. 03/09/2026 · 9 phút đọc 12 Đổi một biến chung lấy biến riêng mỗi luồng: nhanh 385 lần, chỉ đắt thêm 4% Tưởng thread-local storage miễn phí như biến toàn cục, hoặc chậm không đáng dùng? Tôi đo ra ở giữa: truy cập TLS chỉ đắt hơn global 4% (một lệnh đọc con trỏ luồng), nhưng dùng TLS làm bộ đếm cục bộ nhanh hơn atomic chung 385 lần vì xóa sạch tranh chấp. Và chính phép đo TLS suýt cho tôi một con số rác 13.000 lần. 03/09/2026 · 8 phút đọc 13 Thức dậy không có nghĩa là tới giờ: hai cái bẫy của biến điều kiện và cái giá 8,5µs Tưởng cond_wait thức dậy là điều kiện đã đúng, dùng if là đủ, và đánh thức gần như tức thì? Tôi đo: đánh thức tốn ~8,5µs (đúng một chuyển ngữ cảnh), busy-poll nhanh 245 lần nhưng đốt trọn một lõi, và spurious/lost wakeup bắt buộc phải while + mutex — bỏ một trong hai là mời một bug đua tranh không tài nào tái hiện. 03/09/2026 · 9 phút đọc 14 Hàng đợi xử lý ~0 việc vẫn chỉ 6,8 triệu op/s — và gom lô đẩy nó lên 7,4 lần Tưởng throughput hàng đợi chỉ phụ thuộc tốc độ xử lý, hoặc hàng đợi càng lớn càng nhanh? Tôi đo: đẩy/lấy từng phần tử chỉ 6,8 triệu op/s vì chi phí đồng bộ mỗi lần bàn giao, gom lô lên 50,6 (7,4 lần), và kích thước hàng đợi chỉ giúp tới điểm bão hòa. Kẻ giết throughput là đồng bộ per-item, không phải xử lý. 03/09/2026 · 9 phút đọc 15 20.000 việc nhỏ: tạo luồng mỗi việc mất gần 1 giây, thread pool xong trong 8 mili giây Tưởng tạo luồng mỗi việc là ổn cho việc nhỏ, hoặc thread pool là kỹ thuật rườm rà thừa? Tôi đo: 20.000 việc nhỏ kiểu thread-per-task mất 989ms vì chi phí tạo luồng ~47µs lấn át việc thật, còn thread pool nhanh 125 lần với số worker quanh số lõi — quá nhiều worker lại chậm đi. Một chi phí nhỏ nhân số lần lớn thành nút thắt khổng lồ. 03/09/2026 · 9 phút đọc 16 Dồn hết việc cho một worker mà cả nhóm vẫn xong nhanh 5 lần: bí mật của work stealing Tưởng một hàng đợi chung là đủ, hoặc chia việc tĩnh đều là tối ưu? Tôi đo: hàng đợi chung sụt throughput khi đông worker vì tranh khóa, còn work-stealing scale 4,5 lần và tự cân bằng cả khi dồn hết việc vào một worker (nhanh 5 lần) — nhưng trộm cũng có giá, việc tí xíu thì trộm còn chậm hơn. 03/09/2026 · 9 phút đọc 17 25% code chạy tuần tự thì 1000 lõi cũng chỉ nhanh 4 lần: định luật Amdahl Tưởng thêm lõi thì tăng tốc tỉ lệ, và code gần như song song hoàn toàn sẽ scale gần tuyến tính? Tôi đo: một phần tuần tự nhỏ chặn speedup rất mạnh — 25% tuần tự trần ở 4 lần dù bao nhiêu lõi, và thực tế còn dưới cả Amdahl vì chi phí ẩn. Muốn nhanh hơn phải cắt phần tuần tự, không phải đếm lõi. 03/09/2026 · 9 phút đọc 18 Một dòng #pragma nhanh ngang tự viết pthread — nhưng đặt nhầm chỗ thì chậm hơn 105 lần Tưởng cứ thêm #pragma omp parallel for là tự động nhanh? Tôi đo: OpenMP tiện thật, speedup ngang pthread mà chỉ một dòng — nhưng bọc quanh vòng quá nhỏ thì chậm hơn tuần tự 105 lần, chọn sai schedule chậm 1,38 lần, và vẫn dính trần Amdahl. Pragma là công cụ phải đo, không phải nút bấm là nhanh. 03/09/2026 · 12 phút đọc 19 Rắc parallel for lên vòng tính tổng: chương trình không chậm đi, nó nói dối mất 90% Tưởng cứ thêm #pragma omp parallel for lên mọi vòng là song song hóa được? Tôi đo vòng gộp sum += a[i]: parallel ngây thơ cho kết quả SAI, mất 90% cập nhật — không chậm mà sai thầm lặng; sửa bằng atomic thì đúng nhưng chậm 267 lần; chỉ reduction vừa đúng vừa nhanh. Nhận ra phụ thuộc trước khi song song. 03/09/2026 · 11 phút đọc 20 Chia đúng bằng số phần tử cho mỗi lõi mà một luồng vẫn cày gấp 21,7 lần: bẫy cân bằng tải Tưởng chia đều số phần tử cho mỗi lõi là cân bằng tải? Tôi đo: khi mỗi phần tử tốn khác nhau, chia khối làm một luồng thành kẻ tụt hậu (lệch 21,7 lần), tổng thời gian kẹt ở luồng chậm nhất chứ không phải trung bình; chia xen kẽ san đều gần miễn phí. Và một cái rào ngầm suýt che mất toàn bộ hiện tượng khi tôi đo. 03/09/2026 · 11 phút đọc 21 Cùng số phép đọc, một cách chậm hơn 405 lần: sức mạnh của cục bộ bộ nhớ Tưởng đo NUMA được ở mọi máy nhiều lõi, và thêm luồng thì băng thông bộ nhớ tăng tuyến tính? Máy đo chỉ 1 node nên không có NUMA để đo — tôi báo trung thực chứ không bịa số. Nhưng cục bộ thì đo được và khổng lồ: đọc tuần tự nhanh hơn ngẫu nhiên 405 lần, băng thông chung chỉ scale 5,4 lần, chia dữ liệu gần luồng nhanh hơn rải 3,3 lần. 03/09/2026 · 12 phút đọc 22 Cùng một biến, 8 luồng: đọc chung gần như miễn phí, ghi chung đắt gấp 721 lần Tưởng đọc hay ghi một biến dùng chung đều như nhau, và cache coherence trong suốt nên gần như miễn phí? Tôi đo: đọc-chung 0,05 ns/op còn ghi-chung 33 ns/op — ghi đắt 721 lần vì dòng cache phải nảy giữa các lõi; càng nhiều lõi cùng ghi càng chậm, throughput tổng còn sụt. Không phải chia sẻ tốn, mà ghi vào cái chia sẻ mới tốn. 03/09/2026 · 10 phút đọc 23 Bao nhiêu luồng là đủ? 10 lõi mà 80 luồng vẫn nhanh gấp 8 — tùy việc bạn làm Tưởng nhiều luồng thì luôn nhanh hơn, hay cứ đặt số luồng bằng số lõi? Tôi đo hai loại việc trái ngược: việc thuần CPU chững ở ~nproc (thêm luồng vô ích), còn việc chờ-bound thì tối ưu vượt xa nproc — 80 luồng trên 10 lõi vẫn cho throughput gấp 8 lần vì luồng ngủ không chiếm lõi. Không có số luồng vàng. 03/09/2026 · 9 phút đọc 24 2 luồng chậm hơn 1 luồng 11 lần: lock convoy, và vì sao cái đắt không phải khóa Tưởng thêm luồng thì xong nhanh hơn, khóa chỉ tốn đúng thời gian giữ khóa? Tôi đo: khóa một vùng tới hạn tí xíu với 2-8 luồng cho throughput sụp còn 0,09-0,27 lần so một luồng — lock convoy. Cái đắt là BÀN GIAO khóa (mỗi lần đánh thức ~8,5µs), không phải việc trong khóa; gom lô hồi phục 118 lần. 03/09/2026 · 9 phút đọc 25 Đoạn code treo cứng chạy đúng 3089 vòng rồi mới chết: vì sao 'chạy thử thấy chạy' không chứng minh gì Tưởng khóa nhiều mutex thì thứ tự nào chẳng được, chạy thử thấy chạy là ổn? Tôi tái hiện deadlock thật: hai luồng khóa ngược thứ tự treo cứng — nhưng chạy đúng hàng nghìn vòng, treo ở thời điểm khác nhau mỗi lần. Thuốc là áp một thứ tự khóa toàn cục, hoặc trylock+backoff. 03/09/2026 · 10 phút đọc 26 Hết deadlock chưa phải hết lỗi: livelock đốt sạch CPU và writer chờ 30ms sau dòng reader Tưởng không deadlock, không treo là ổn, và trylock tránh deadlock nên an toàn? Tôi đo: livelock chạy hết CPU mà phí 5 lần vì backoff đồng nhịp, và rwlock để dòng reader bỏ đói writer — đọc nhiều hơn ghi 30.000 lần, writer chờ tới 30ms. 'Không treo' không bằng 'mọi luồng đều tiến'. 03/09/2026 · 10 phút đọc 27 Semaphore không phải 'mutex biết đếm' — và K càng lớn càng nhanh là sai Tưởng semaphore chỉ là mutex đếm, K càng lớn càng nhanh? Tôi đo: semaphore chặn CỨNG số luồng đồng thời ở đúng K (mutex chỉ là K=1), throughput tăng theo K rồi bão hòa ở K=8; và khác mutex, semaphore không có chủ sở hữu nên báo hiệu được giữa hai luồng khác nhau — thứ mutex không làm được. 03/09/2026 · 10 phút đọc 28 Một luồng chậm trong tám kéo cả tính toán chậm 1,75 lần: cái bẫy khuếch đại của barrier Tưởng barrier rẻ, cứ thêm cho chắc? Tôi đo: mỗi rào tốn 8 tới 41 micro giây, tăng theo số luồng vì phải đánh thức cả N luồng; và rào chờ luồng chậm nhất mỗi pha — một luồng nặng gấp 4 trong tám làm cả tính toán 500 pha chậm 1,75 lần. Barrier khuếch đại mọi mất cân bằng tải. 03/09/2026 · 9 phút đọc 29 std::async chạy 20.000 việc nhỏ chậm hơn tuần tự 1724 lần — API đẹp không đổi được vật lý Tưởng future/async tự động nhanh và rẻ? Tôi đo bằng C++: future.get() là một điểm đồng bộ chặn tới khi promise set, và std::async mặc định tạo một luồng mới cho mỗi task — chạy hai vạn task nhỏ bằng async chậm hơn tuần tự 1724 lần. Future tiện cho một kết quả, không phải phép màu song song. 03/09/2026 · 10 phút đọc 30 Gộp lô đẩy throughput lên 2000 lần — nhưng 'lô càng to càng tốt' là cái bẫy Tưởng tối ưu đồng bộ là làm mỗi lần đồng bộ nhanh hơn, hoặc batch càng lớn càng tốt? Tôi đo: gộp lô để giảm SỐ LẦN đồng bộ đẩy throughput từ 32 triệu lên 64,6 tỉ ops/giây — 2000 lần; nhưng độ trễ mỗi item cũng tăng ~94 lần theo kích thước lô. Batch tối ưu là cân bằng, không phải cực đại. 03/09/2026 · 9 phút đọc 31 CAS báo 'thành công' mà cấu trúc vẫn hỏng lặng lẽ: bài toán ABA và liều thuốc gần như miễn phí Tưởng CAS thành công nghĩa là không ai đụng vào, và lock-free cứ CAS là an toàn? Tôi ép giá trị đổi A rồi B rồi A lại giữa lúc đọc và lúc CAS: CAS vẫn thành công dù ngăn xếp đã hỏng — đó là ABA. Versioned CAS bắt được tận gốc, và đo ra chỉ đắt hơn 1%. 03/09/2026 · 10 phút đọc 32 Đường đọc nhanh hơn rwlock 374 lần trong nhân Linux — bí mật là không ai ghi chung Tưởng đọc trong cấu trúc lock-free cũng phải đồng bộ như rwlock, và thu hồi bộ nhớ lock-free là miễn phí? Tôi đo: đọc kiểu RCU ghi ô riêng nên scale gần tuyến tính, nhanh 374 lần rwlock ở 8 luồng — nhưng cái 'miễn phí' đó được trả ở writer, phải chờ grace period rồi mới free. Tối ưu chỉ dời chi phí, không xóa. 03/09/2026 · 10 phút đọc 33 Cách đọc nhanh hơn rwlock 862 lần mà luôn thấy dữ liệu nhất quán — và cái giá của nó Tưởng seqlock chỉ là rwlock nhanh hơn, và reader luôn đọc được ngay? Tôi đo: reader seqlock chỉ đọc một bộ đếm nên scale gần tuyến tính (nhanh 862 lần rwlock ở 8 luồng) và không bao giờ thấy snapshot rách — nhưng phải đọc lại khi có writer, ghi dồn thì retry tới 12,7 lần mỗi đọc. Mỗi công cụ đồng bộ là một đổi chác riêng, không phải bậc thang nhanh dần. 03/09/2026 · 10 phút đọc 34 Chạy hoàn hảo trên laptop, hỏng trên server ARM: cái bẫy 20 năm của double-checked locking Tưởng kiểm null rồi khóa rồi kiểm lại là đủ, và DCL chỉ là mẹo tránh khóa? Tôi đo: fast-path đọc atomic không khóa nhanh 314 lần always-lock — nhưng DCL đúng bắt buộc có rào bộ nhớ (acquire/release), thiếu nó luồng khác thấy con trỏ đã publish mà object chưa khởi tạo xong. Một bug ẩn kỹ tới mức Java mất nhiều năm mới thừa nhận. 03/09/2026 · 9 phút đọc 35 Con sông sâu trung bình 1 mét vẫn dìm chết người: vì sao 'latency trung bình' nói dối Tưởng throughput cao là hệ nhanh, và đo latency bằng trung bình là đủ? Tôi đo từng thao tác dưới tranh chấp: throughput và latency là hai thứ khác nhau có thể cùng tệ đi, và latency là một phân phối lệch — ở 8 luồng trung vị chỉ 125ns nhưng p99 vọt lên 32.292ns, gấp 258 lần. Trung bình giấu cái đuôi mà người dùng thật sự gặp. 03/09/2026 · 9 phút đọc 36 Hàng đợi vô hạn nuốt 43MB trong nửa giây rồi vẫn phình: vì sao 'buffer thật to' là quả bom Tưởng cứ hàng đợi lớn (hoặc vô hạn) để không mất việc, và producer đẩy càng nhanh càng tốt? Tôi đo: producer nhanh hơn consumer với hàng đợi vô hạn thì độ sâu chạm 5,46 triệu item, latency nổ lên 270ms, bộ nhớ phình mãi; đặt hàng đợi có chặn thì producer tự ghìm về tốc độ consumer, latency có trần, bộ nhớ gần 0. Backpressure là khác biệt giữa ổn định và sụp đổ. 03/09/2026 · 9 phút đọc 37 Chia một khóa thành 512 lối vẫn có bẫy: mỗi lần tính tổng lại đắt thêm 30 lần Tưởng một cấu trúc chung với một khóa là đủ, hoặc càng nhiều shard càng tốt? Tôi đo: một khóa chung sụp từ 229 xuống 35,7 triệu op/s khi đông luồng, chia nhiều shard giúp throughput scale 3 lần — nhưng càng nhiều shard, tính tổng toàn cục càng đắt (65 nghìn shard mất 32,8µs). Sharding dời chi phí chứ không xóa. 03/09/2026 · 9 phút đọc 38 Atomic 'lock-free' vẫn chậm 27 lần khi đông luồng — và không hề nhanh hơn mutex Tưởng atomic là lock-free nên luôn rẻ, và luôn nhanh hơn mutex? Tôi đo: fetch_add trên một atomic chung 1,6ns khi một luồng nhưng 44ns khi tám luồng — đắt theo số luồng vì cùng nảy một dòng cache; CAS-loop tệ nhất (119ns); còn per-thread nhanh 96 lần. Lock-free nói về ngữ nghĩa, không về chi phí. 03/09/2026 · 9 phút đọc 39 'Code tôi scale 8 lần trên 8 lõi' — 8 lần so với cái gì? Chọn sai mẫu số, con số nói dối Tưởng speedup = thời gian 1 luồng / N luồng là đủ, và scaling tuyến tính tới số lõi? Tôi đo: 10 lõi chỉ cho 4,65x (không phải 10x), và nếu lấy baseline sai (bản song song 1 luồng thay vì tuần tự tốt nhất) thì con số bị thổi phồng đều 6,2 lần. Speedup là một phân số, và mẫu số nào cũng nói dối được. 03/09/2026 · 10 phút đọc 40 Hàm 'nóng nhất' trong profiler lại vô can: 8 luồng chỉ chạy như 1,27 lõi vì bận chờ khóa Tưởng hàm nóng nhất trong profiler là chỗ cần tối ưu, và CPU bận nghĩa là thiếu CPU? Tôi đo: một chương trình 8 luồng chỉ đạt song song hiệu quả 1,27 lõi vì chờ khóa 81% thời gian — mà hàm 'nóng' nhất lại hoàn toàn vô can. Đọc profiler đa luồng phải nhìn CPU/wall và thời gian chờ. 03/09/2026 · 9 phút đọc 41 volatile không cứu code đa luồng: đếm chung vẫn mất 50%, và -O2 giấu luôn cuộc đua Tưởng biến chung đọc/ghi bình thường vẫn chạy được, và volatile là đủ cho đa luồng? Tôi đo: hai luồng tăng một biến non-atomic mất ~50% cập nhật, đọc cờ chung non-atomic bị -O2 hoist thành treo vĩnh viễn — chỉ atomic mới đảm bảo. Và trớ trêu, -O2 gập mất cuộc đua ngay trong phép đo về nó. 03/09/2026 · 8 phút đọc 42 8 luồng chậm hơn 1 luồng dù tôi không viết một khóa nào — thủ phạm nằm trong rand() Tưởng thư viện chuẩn thread-safe nên gọi thoải mái từ nhiều luồng, và code không có khóa thì phải scale? Tôi đo: rand() có khóa ẩn khiến tổng throughput sụp từ 258 xuống 6,5 triệu op/s ở 2 luồng, 8 luồng vẫn chậm hơn 1 luồng — trong khi rand_r() cùng thuật toán scale 5,1 lần. 03/09/2026 · 8 phút đọc 43 Cùng một cách song song hóa: vòng này SIMD chỉ nhanh 1,12 lần, vòng kia 2,49 lần Tưởng vector hóa cho Nx, đa luồng cho số-lõi lần, nhân lại ra tích? Tôi đo: một vòng memory-bound chỉ được 1,12 lần từ SIMD dù mã máy có lệnh vector (băng thông chặn), còn vòng compute-bound được 2,49 lần từ SIMD ngay trên một lõi. Tăng tốc phụ thuộc nút thắt, không phải kỹ thuật. 03/09/2026 · 7 phút đọc 44 Một lần chạy nói 'tối ưu này chậm 2,9 lần' — lặp 15 lần lấy min: hóa ra nhanh 4,36 lần Tưởng chạy một lần mỗi bên rồi so là đủ để biết một thay đổi đồng thời có đáng? Tôi đo: một lần chạy trúng nhiễu (outlier 13ms) đảo ngược cả kết luận — nói padded chậm 2,9 lần trong khi thật ra nó nhanh 4,36 lần. Nhiễu chỉ cộng, không trừ — nên phải lặp và lấy min. 03/09/2026 · 8 phút đọc 45 45 phép đo về code đồng thời, và một sự thật: trực giác của bạn gần như luôn sai Bài kết của sê-ri 45 phần đo thật về đồng thời. Ba tầng bài học và những con số đáng nhớ — tạo luồng 47µs, 10 lõi chỉ 4,65 lần, atomic tranh chấp chậm 27 lần, false sharing 4 lần — cùng một điều xuyên suốt: với đồng thời, đoán thì sai, chỉ đồng hồ mới nói thật. 03/09/2026 · 7 phút đọc