Tiếp sau bài Kotlin Coroutines Basic Concepts. Bài này mình sẽ tận dụng những kiến thức trên để giải quyết một vấn đề trong Concurrent
đó là Race Condition
bằng ý tưởng Map-Reduce
. Bài này khá ngắn nhưng lại đề cập được 2 chủ đề rất hay là Race Condition
và Map-Reduce
nên các bạn hãy đọc tới cuối bài nhé ;))
Nội dung bài viết:
- What is Race Condition?
- How to resolve Race Condition?
- What is Map-Reduce?
- Resolve Race Condition with Map-Reduce
1. What is Race Condition?
Hãy nhìn video sau:
và tưởng tượng các chú chó làthread
còn trái banh là resource
;))Không cần giải thích nhiều thì chắc các bạn cũng thấy cũng thấy resource
sẽ có thể không chính xác hoặc toàn vẹn nếu có nhiều thread
cùng tranh chấp trong một thời điểm.
2. How to resolve Race Condition?
Nguyên nhân của Race Condition
là do tranh chấp resource
. Vậy chỉ cần giải quyết được vấn đề này sẽ giải quyết được Race Condition
, và ta có 2 “trường phái” là:
1. Sử dụng Synchronizations[1] hoặc Atomic Operations[2]
2. Tránh chia sẻ trạng thái
Quay lại ví dụ về các chú chó và trái banh thì 2 cách giải quyết sẽ như sau:
- Sẽ cũng chỉ có 1 trái banh và các chú cho phải đợi tới lượt mình chơi - các chú chó chắc sẽ không được vui 😂.
- Sẽ có nhiều trái banh cho các chú chó và chắc chắn chú chó nào cũng vui 💪.
→ vậy chỉ cần phụ thuộc vào điều kiện anh chủ ;))
Trong thực tế, thì trước đây khi phần cứng chưa phát triển, các hệ thống máy tính chỉ có một core, bộ nhớ RAM đắt đỏ thì #1 là sự lựa chọn tốt hơn nhưng tới thời điểm hiện tại mình tin rằng #2 là giải pháp tối ưu hơn.
Tuy nhiên vẫn có một số trường hợp bắt buộc phải dùng #1 như: số dư tài khoản ngân hàng, chỉ số chứng khoán…
3. What is Map-Reduce?
Đọc tới đây chắc bạn cũng đưa ra nhận định #2 là lựa chọn tối ưu để giải quyết Race Condition
trong thời điểm hiện tại. Nhưng làm thế nào để hiện thực #2? Một trong những cách hiện thực là Map-Reduce
. Vậy Map-Reduce
là gì?
Map-Reduce lần đầu tiên được giới thiệu bởi Jeffery Dean và Sanjay Ghemawat lúc đó đang làm việc ở Google vào năm 2004, và là ý tưởng cơ bản để hiện thực Hadoop. Về cơ bản, đây là cách thực hiện của tinh thần chia để trị. Khi thực thi, sẽ có 2 bước là:
- Map: chia dữ liệu cần xử lý thần các phần nhỏ và xử lý các phần nhỏ đó.
- Reduce: tổng hợp dữ liệu đã xử lý để cho ra kết quả cuối cùng.
Lý thuyết hơi khó hiểu nên bạn xem hình này nha:
đây ví dụ “Word Count” trong bài Hadoop MapReduce deep diving and tuning . Nhiệm vụ là cần đếm số lần xuất hiện của một từ trong phần Input. Với bước Map được chia thành 2 bước nhỏ: Splitting và Mapping, Reduce được chia thành 2 bước nhỏ: Shuffling và Reducing.
Resolve Race Condition with Map-Reduce
Đây là phần chính của bài viết. Mình sẽ implement ví dụ “kinh điển” của Race Condition
là increase một biến counter
bằng 3 cách: increase bình thường, increase với Map-Reduce và increase với nhiều thread và AtomicLong.
|
|
kết quả sẽ show ra như sau:
increaseSync: counterSync [1000000000] - time [304001418]
increaseSync with Map-Reduce: counterMapReduce [1000000000] - time [171316295]
increaseWithAtomic: atomicCounter [1000000000] - time [19268418252]
Ta có thể thấy thời gian của increaseSync with Map-Reduce
là nhanh nhất ta xem là 1x thì increaseSync
là 1.8x và thật kinh khủng khi increaseWithAtomic
là 112.5x. Số liệu chạy lại có thể khác nhưng từ đây có thể thấy trong trường hợp thời gian thực hiện toán tử là nhanh và thời gian để đảm bảo shared state
luôn đúng là chậm thì Sử dụng Synchronizations hoặc Atomic Operations là không hiệu quả.
Kết: Khi giải quyết Race Condition
trong thời điểm hiện tại thì cách Tránh chia sẻ trạng thái đang là giải pháp tối ưu trong hầu hết các trường hợp, Map-Reduce
là một trong những hiện thực của cách trên nhưng vẫn còn những cách khác giải quyết những vấn đề phức tạp hơn. Mong các bạn đón đọc phần tiếp theo của loại bài viết về Kotlin Coroutines
để được nhiều vấn đề trong Concurrent
và cách giải quyết nhé.
Phần code sample mình update vào repo này nhé. Cảm ơn các bạn đã đọc tới đây.