iOS Concurrency - Phần 3.1: Grand Central Dispatch

What is Grand Central Dispatch (GCD)?

GCD được giới thiệu lần đầu tiên trong iOS4, nó là một thư viện Apple cung cấp nhằm hổ trợ việc chạy những tasks song song nhằm tối ưu hiệu năng cho những thiết bị có bộ xử lý đa lõi (multi core processor). Mặc dù đây là một thư viện rất tuyệt vời nhưng nhiều developer tránh sử dụng GCD và chọn một cách dễ hơn là NSOperationQueue. Đây là một thực trạng trước khi Apple ra mắt Swift 3. Sở dĩ có vấn đề này bởi vì cú pháp của GCD rất khó nhớ và không dễ dàng để viết. Nó khá tương đồng với ngôn ngữ cấp thấp như C và dĩ nhiên rằng không thể nào dễ viết và thân thiện giống với Swift. Tuy nhiên GCD đã thay đổi ngoạn mục trong Swift 3. Cú pháp GCD mới dễ nhớ hơn, thân thiện với developer hơn và dĩ nhiên là nó tương đồng với Swift-style. Do đó, developers sẽ cảm thấy phấn khích khi sử dụng GCD để tối ưu performance cho những đứa con tinh thần của họ.

Queues

Mình đã đề cập một số khái niệm, thuật ngữ khi chúng ta nói về concurrency ở những bài trước. Hôm nay mình sẽ giải thích một thuật ngữ mà bạn hay gặp trong GCD đó chính là queues. Queue tiếng việt có nghĩa là hàng đợi. Mà hàng đợi thì lúc nào cũng phải tuân theo quy tắc FIFO (first in, first out). Cái này giống như khi bạn xếp hàng để mua vé ở rạp phim, người nào tới trước sẽ được mua vé trước và lần lượt như vậy cho tới khi hết hàng. GCD cung cấp cho chúng ta Dispatch Queue để quản lý những tasks mà bạn submit tới queue và chạy chúng theo thứ tự FIFO. Điều này đảm bảo rằng task đầu tiên được thêm vào queue sẽ là task đầu tiên được start sau đó lần lượt các task được start theo thứ tự đến hết queue. GCD cung cấp cho chúng ta 2 loại hình của DispatchQueue: Serial Queues và Concurrent Queues.

Serial Queues & Concurrent Queues

Serial Queue (hàng đợi tuần tự):

Chỉ có một task được chạy tại một thời điểm và mỗi task được bắt đầu (start) khi task phía trước đã hoàn thành (finished). Tuy nhiên chúng ta vẫn có thể chạy những tasks đồng thời (concurrent) bằng cách sử dụng nhiều serial queue. Ví dụ bạn có thể tạo 2 serial queues, mỗi serial queue chỉ chạy một task ở một thời điểm nhưng 2 tasks này vẫn chạy đồng thời do 2 serial queues chạy đồng thời. Một trường hợp thực tế là khi bạn đi mua vé ở rạp phim, bạn vẫn phải xếp hàng trong serial queue để đảm bảo rằng chỉ có một bạn mua vé tại quầy đó ở một thời điểm. Một quầy vé (shared resource) không thể bán vé cho nhìu bạn cùng một lúc mà các bạn phải xếp hàng tuần tự. Tuy nhiên điều này không có nghĩa là rạp phim chỉ phục vụ một khách hàng ở một thời điểm. Do có rất nhiều bạn mua vé nên rạp phim sẽ mở nhiều quầy bán vé chạy đồng thời (concurrent). Như thế chúng ta vẫn thể hiện thực concurrent bằng cách sử dụng nhiều serial queue. Serial queue là một trong những cách tuyệt vời cho việc quản lý tài nguyên dùng chung (shared resource). Nó cung cấp một cách truy cập tuần tự (serial) tới tài nguyên dùng chung (shared resource) nhằm ngăn ngừa race condition (mình đã đề cập vấn đề này ở các bài trước).

Concurrent Queue:

Cho phép nhiều tasks chạy cùng một thời điểm. Hàng đợi concurrent đảm bảo những tasks này start theo thứ tự mà chúng được thêm vào queue nhưng chúng vẫn chạy đồng thời. Chúng ta sẽ không biết được thời gian mà một task chạy cũng như số lượng task chạy đồng thời tại một thời điểm, điều này phụ thuộc vào sự quyết định của hệ thống. Ví dụ chúng ta submit 3 task theo thứ tự: task1, task2, task3 vào concurrent queue. Những task này được chạy đồng thời và start theo thứ tự chúng ta đã sắp xếp. Tuy nhiên, đôi khi task3 lại kết thúc trước task2. Điều này do hệ điều hành quyết định.

Type of queues

GCD cung cấp 3 loại queue chính: Main queue, Global queue, Custom Queue.

Main queue (Main dispatch queue):

Là một loại serial queue mà nó chạy những tasks trên main thread của ứng dụng. Được sử dụng để update UI của app, thực hiện những task liên quan đến update UIViews hay posting notifications. Bởi vì nó là serial queue nên chỉ có một task được chạy tại một thời điểm, do đó bạn sẽ bị block UI khi chạy những task nặng trên main queue (vd: download image từ server về). Mặc định hệ thống chỉ tạo duy nhất 1 queue này.

Global dispatch queues (Global queues):

Là những concurrent queues. Hệ thống cung cấp 4 global concurent queues khác nhau bởi độ ưu tiên được đặc tả bởi thuộc tính Quality of Service (QoS) Class. Các bạn có thể xem thêm ở đây: https://developer.apple.com/library/content/documentation/Performance/Conceptual/EnergyGuide-iOS/PrioritizeWorkWithQoS.html

Custom Queues:

Là những queue bạn tự tạo, chúng có thể là concurrent hay serial.

Những gì mình sẽ nói tiếp?

Thông qua bài giới thiệu nho nhỏ này, các bạn chắc hẳn đã nắm được một cách tổng quan về GCD và một số thuật ngữ trong GCD. Ở bài tiếp theo mình sẽ giới thiệu cách xử lý background task khi chúng ta gặp phải một tác vụ nặng, đòi hỏi thời gian lâu. Thêm vào đó chúng ta sẽ tìm hiểu việc tăng cường trải nghiệm người dùng (UX) bằng cách sử dụng dispatch queue để delay việc hiển thị gợi ý (prompt). Hẹn gặp các bạn ở những bài viết kế tiếp trong chuỗi series về iOS concurrency.

Tài liệu tham khảo

https://www.raywenderlich.com/60749/grand-central-dispatch-in-depth-part-1 https://www.raywenderlich.com/148513/grand-central-dispatch-tutorial-swift-3-part-1 https://www.appcoda.com/ios-concurrency/