Mở đầu loại bài viết về Kotlin Coroutines mình sẽ giải thích khác khái niệm trong Coroutines và tương ứng với các khái niệm sẽ có thêm ví dụ. Qua đó mong bạn sẽ có kiến thức nền về Coroutines và tìm hiểu nó nhanh hơn.
Các khái niệm sẽ giải thích trong bài này:
1. Dispatchers
Đúng như cái tên. Dispatcher có nhiệm vụ điều phối một hoặc nhiều thread làm nhiệm vụ thực thi coroutine. Có các loại Dispatcher như sau:
- Dispatchers.Default: là dispatcher mặc định sẽ được sử dụng nếu không khai báo tường minh trong Scope Builder. Nó sử dụng một
common poolđược chia sẻ bởi các thread nền.Dispatchers.Defaultthích hợp với các tính toán cần nhiều tài nguyên CPU - Dispatchers.IO: được thiết kế để sử dụng cho các thao tác
IO-intensive blocking operationsnhư đọc/ghi file hay blocking socket I/O - Dispatchers.Unconfined: đây là một dispatcher khá lạ. Trong docs cũng nói nó không thường được sử dụng trong code ;)). Dispatchers này sẽ không chỉ định thread nào sẽ thực thi. Nó có nghĩa là khi khởi chạy nó sẽ được chạy bởi thread đang chạy nó, khi
resumelại sau khisuspendthìCoroutinessẽ quyết định thread sẽ thực thi - ThreadPool cụ thể được chỉ định được tạo ra bởi
newSingleThreadContexthoặcnewFixedThreadPoolContext - Các Executor được convert bởi
asCoroutineDispatcher
| |
2. Scope
Các coroutine được khởi chạy trong CoroutineScope. Mục đích của việc này để quản lý resource. Hãy tưởng tượng khi ta cần thực hiện một tác vụ nặng nào đó trong một hoặc nhiều coroutine, nhưng giữa chừng tác vụ đó không cần thiết nữa, lúc này ta chỉ cần cancel() scope chứa các coroutine của tác vụ nặng trên. Một đặc điểm khác của CoroutineScope là nó có thể chứa nhiều CoroutineScope con.
GlobalScope
GlobalScope được xem như là scope cha của tất cả các CoroutineScope trong ứng dụng. GlobalScope không thể bị cancel() và sẽ tồn tại xuyên suốt vòng đời ứng dụng. Ngoài ra việc sử dụng được khuyên là KHÔNG NÊN. Bạn có thể xem thêm ở bài The reason to avoid GlobalScope để hiểu nguyên nhân nhé.
Scope Builder
Như đã nói ở trên các coroutine sẽ được khởi chạy trong các Scope Builder sau:
runBlocking: chạy một
coroutinevà sẽ block[1] đến khicoroutinebên trong chạy xong. Không nên sử dụng function này trong mộtcoroutinevì nó được thiết kế để làmcầu nốicode thường với các thư viện được viết theosuspending style, thường được sử dụng cho hàmmainvà trong test.coroutineScope: Tạo ra một
CoroutineScopemới. Scope được tạo mới này là con của scope bên ngoài nhưng overrides lại Job. Function này được thiết kết đểparallel decomposition, nghĩa là khi có bất cứ mộtcoroutinenào fail trong scope này thì cáccoroutineđang đợi xử lý trong scope này cũng sẽ đượccancel.launch: Tạo ra một
CoroutineScopemới, sẽ không block[2] thread hiện tại và sẽ trả về một Job.async: Tạo ra một
CoroutineScopemới, sẽ không block2 thread hiện tại và sẽ trả về một Deferred. Như vậyasyncđược dùng khi cần kết quả trả về khi gọi cònlaunchthì không.
| |
3. Context
Mỗi coroutine trong Kotlin đều có một context được thể hiện bằng một instance của interface CoroutineContext. Context này là một tập các thành phần cấu hình cho coroutine, trong đó 2 thành phần quan trọng là Job và Dispatcher.
Context là một immutable. Nhưng ta có thể dùng toán tử plus để tạo ra một context mới.
| |
4. Suspending Function
Suspending Function được xem xương sống của Kotlin Coroutines. Khi đó, các function bên trong Suspending Function sẽ được gọi mà không bị block1. Như thế thread đang handle cho Suspending Function sẽ được trả lại cho JVM và được dùng cho các tác vụ khác.
Suspending Function phải chạy trong một coroutine thì mới có tác dụng nhé ;))
| |
5. Job
Như đã đề cập ở Context Job là thành phần không thể thiếu trong context. Nó cho phép ta cancel(), join() hoặc start() coroutine tương ứng với job đó. Ngoài ra nhờ có job mà ta biết được trạng thái của một coroutine. Các trạng thái của coroutine có thể được biển diễn ở hình dưới:
wait children
+-----+ start +--------+ complete +-------------+ finish +-----------+
| New | -----> | Active | ---------> | Completing | -------> | Completed |
+-----+ +--------+ +-------------+ +-----------+
| cancel / fail |
| +----------------+
| |
V V
+------------+ finish +-----------+
| Cancelling | --------------------------------> | Cancelled |
+------------+ +-----------+
| |
6. Deferred
Deferred cũng là một Job nhưng nó chứa kết quả khi coroutine hoàn thành. Deferred được tạo bằng async mà mình đã đề cập ở ScopeBuilder hoặc khởi tạo trực tiếp bởi CompletableDeferred
| |
Phần code sample mình update vào repo này nhé. Cảm ơn các bạn đã đọc tới đây.