1. GCD là gì?
Grand Central Dispatch (GCD) là 1 API được dùng để quản lý các concurrent operations giúp cải thiện khả năng phản hồi của app bằng cách đưa các task handle lâu ra ngoài background. Dễ dàng làm việc với mô hình hơn là locks và threads.
Trong iOS, một quy trình hoặc ứng dụng bao gồm một hoặc nhiều thread. Operating system scheduler quản lý các thread độc lập với nhau. Mỗi thread có thể thực thi đồng thời, nhưng tùy thuộc vào hệ thống để xem thử nó có được tiến hành không, khi nào thì nó xảy ra và nó xảy ra như thế nào.
Các thiết bị single-core có được concurrency thông qua một phương pháp gọi là time-slicing (cắt thời gian). Chúng chạy một thread, thực hiện chuyển đổi ngữ cảnh, sau đó chạy một thread khác. Mặt khác các multi-core devices tiến hành multiple threads cùng lúc thông qua cơ chế song song.
GCD được xây dựng dựa trên threads. Chi tiết hơn, nó quản lý một thread pool chung. Với GCD ta code hoặc đưa đoạn code của mình vào trong dispatch queues và GCD sẽ quyết định thread nào sẽ thực thi nó.
Khi xây dựng code thì bạn sẽ thấy code đôi khi cần cho chúng chạy song song, đôi khi không nên. Điều này cho phép bạn sử dụng GCD để tận dụng concurrent execution.
Lưu ý rằng GCD quyết định mức độ song song mà nó đòi hỏi dựa trên hệ thống và tài nguyên hệ thống có sẵn. Điều quan trọng cần lưu ý là parallelism yêu cầu concurrency, nhưng concurrency không đảm bảo parallelism. Để hiểu rõ vấn đề này, các bạn đọc thêm ở đây: https://text.relipasoft.com/2016/12/dong-thoi-khong-phai-la-song-song-concurrency-is-not-parallelism/
Về cơ bản, concurrency là về cấu trúc trong khi parallelism là về thực thi.
2. Queues
Như đã biết, GCD hoạt động trên dispatch queues thông qua 1 class tên là `DispatchQueue` . Bạn chia nhỏ công việc rồi để sắp xếp nó với cái queue này và GCD sẽ execute chúng theo thứ tự FIFO (First In, First Out), đảm bảo rằng nhiệm vụ đầu tiên được gửi là nhiệm vụ đầu tiên được bắt đầu. Dispatch queues là thread-safe, nó có nghĩa là bạn có thể access chúng từ multiple threads một cách đồng thời. Ta cần hiểu rõ cách mà dispatch queues cung cấp threads 1 cách an toàn cho code của bạn. Vấn đề là chọn loại dispatch queue sao cho hợp lý và hàm dispatching hợp lý để đưa code bạn vào.
Queues có thể là serial hoặc concurrent. Serial queues đảm bảo chỉ có 1 task duy nhất tại bất kì thời điểm nà. GCD kiểm soát thời gian execution. Bạn sẽ không biết được khoảng thời gian giữa 1 task bắt đầu và 1 task đã kết thúc.
Concurrent queues cho phép run multiple task đồng thời. The queue đảm bảo những task bắt đầu theo thứ tự mà ta thêm chúng. Các task có thể hoàn thành theo bất kỳ thứ tự nào và ta không biết gì về thời gian cần để thực hiện tác vụ tiếp theo, cũng như số lượng tác vụ đang chạy tại bất kỳ thời điểm nào. Code của bạn không nên dựa vào những implementation này.
Để ý cách Task 2, Task 3 bắt đầu nhanh như thế nào trong khi Task 1 mất một lúc để bắt đầu sau Task 0. Ngoài ra Task 3 finished trước task 2, trong khi nó bắt đầu sau.
Quyết định khi nào bắt đầu 1 task HOÀN TOÀN PHỤ THUỘC vào GCD. Nếu thời gian tiến hành 1 task trùng với task khác, GCD sẽ quyết định liệu nó có nên run trên 1 core khác, liệu nó có cho availabe không thay vì perform 1 context switch để run 1 task khác.
3. Các kiểu queues:
a. GCD cung cấp 3 loại types of queues:
- Main queue: run trên main thread and là serial queue.
- Global queue: là 1 concurrent queues mà được shared trên toàn system. Có bốn loại queues với priorities khác nhau: high, default, low, and background. Background priority queue là lowest priority trong bất kì I/O activity để giảm thiểu negative system impact.
- Custom queues: queues mà bạn create ra có thể là serial or concurrent. Nói chung loại này cuối cùng cũng như global queues.
Khi bạn gửi task đến global concurrent queues, ta dùng Quality of Service (QoS) class property để phân biệt priority của chúng và chỉ cho GCD xác định được priority để run.
b. QoS classes bao gồm:
- User-interactive: Task này nói là bạn phải hoàn thành ngay lập tức để cung cấp 1 trải nghiệm smooth cho người dùng. Dùng cái này khi bạn muốn dùng cho UI updates, event handling hay các việc nhỏ nhỏ mà yêu cầu độ trễ thấp. Tổng số công việc được thực hiện trong lớp này trong quá trình thực hiện ứng dụng nên nhỏ thôi. Và cái này nên chạy trên main thread.
- User-initiated: User sẽ initiate những asynchronous tasks từ UI. Dùng chúng khi user đang chờ kết quả trả về liền và những task yêu cầu tương tác người dùng tiếp. Phần này xem như global queue với priority high.
- Utility: Thao tác này thể hiện các tasks dài hạn, kiểu như a user-visible progress indicator. Sử dụng cho các việc computations, I/O, networking, continuous data feeds and similar tasks. Lớp này được thiết kế để tiết kiệm năng lượng. Phần này xem như global queue với low priority.
- Background: Cái này đại diện cho tasks ngầm, mà user không có biết. Dùng nó cho prefetching, maintenance, and other tasks mà không yêu cầu user interaction và không ràng buộc thời gian. Phần này xem như global queue với priority là background.