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.Default
thí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 operations
như đọ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
resume
lại sau khisuspend
thìCoroutines
sẽ quyết định thread sẽ thực thi - ThreadPool cụ thể được chỉ định được tạo ra bởi
newSingleThreadContext
hoặ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
coroutine
và sẽ block[1] đến khicoroutine
bên trong chạy xong. Không nên sử dụng function này trong mộtcoroutine
vì nó được thiết kế để làmcầu nối
code thường với các thư viện được viết theosuspending style
, thường được sử dụng cho hàmmain
và trong test.coroutineScope: Tạo ra một
CoroutineScope
mớ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ộtcoroutine
nà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
CoroutineScope
mới, sẽ không block[2] thread hiện tại và sẽ trả về một Job.async: Tạo ra một
CoroutineScope
mớ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ònlaunch
thì 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.