12/08/2018, 15:25

Kiến thức phỏng vấn iOS _ Phần 2: Grand Central Dispatch (GCD) và ứng dụng

Tiếp theo phần 1, hôm nay chúng ta sẽ đi qua phần 2 của series này là Grand Central Dispatch(GCD) và ứng dụng nó vào thực tiễn. 1. Grand Central Dispatch(GCD) là gì? Grand Central Dispatch(GCD) là 1 một low-level API được xây dựng bởi Apple, dùng để làm cái mà người ta thường gọi là đa nhiệm ...

Tiếp theo phần 1, hôm nay chúng ta sẽ đi qua phần 2 của series này là Grand Central Dispatch(GCD) và ứng dụng nó vào thực tiễn.

1. Grand Central Dispatch(GCD) là gì?

Grand Central Dispatch(GCD) là 1 một low-level API được xây dựng bởi Apple, dùng để làm cái mà người ta thường gọi là đa nhiệm (multiasking), dùng để thực hiện các tác vụ ngoài main thread, giúp cải thiện khả năng response của app bằng cách chuyển các tác vụ nặng, tốn nhiều thời gian vào các threads, queues để main thread chỉ phục vụ việc hiển thị giao diện và tương tác của người dùng.

Trong bài này chỉ dùng cú pháp và tên gọi cho Swift 3 trở lên, vì thế mà sẽ có các classes và data structures mới.

Vì GCD quá rộng nên chúng ta chỉ đi qua những cái đặc trưng và hay hỏi trong phỏng vấn mà thôi.

2. DispatchQueue

GCD cung cấp 1 class có tên là DispatchQueue để quản lý những tác vụ mà bạn submit và execute chúng.

Có các loại queues phổ biến như sau:

//main queue: chạy trên main thread và là một serial queue
let main = DispatchQueue.main

//global queue: concurrent queues của hệ thống quản lý, có 4 mức độ ưu tiên: high, default, low và background
let background = DispatchQueue.global() 

//custom queue: chúng ta tự tạo ra, có thể là tuần tự(serial) hoặc đồng thời(concurrent)
let custom = DispatchQueue(label: "custom_queue")

Điểm nhấn ở Swift 3: Khi bạn setup một global concurrent queue, thì bạn không cần phải đặc tả đọ ưu tiên trực tiếp độ ưu tiên của nó. Thay vào đó thì đặc tả 1 property là qos, Quality of Service. Cái struct này nó có các case để ta lựa chọn:

  • background : dành cho những tasks mà user không cần phải biết trước. Sử dụng cho prefetching data, maintenance, hoặc những task mà không bắt buộc có sự tương tác của user. Nó sẽ được mapped với background priority của global queue.
  • utility : Thường dành cho các tác vụ chạy lâu, có hiển thị chỉ số tiến trình. Ví dụ cho việc tính toán, I/O, networking, sự liên tục của dữ liệu và các tác vụ tương tự. Cái này dùng để tiết kiệm năng lượng. Nó sẽ được mapped với low priority của global queue.
  • userInitiated : Các tác vụ được khởi tạo từ UI và được performed bất đồng bộ. Được sử dụng khi user chờ có kết quả ngay lập tức, cho các tác vụ bắt buộc để tiếp tục tương tác với người dùng. Nó sẽ được mapped với high priority của global queue.
  • userInteractive : Các tác vụ cần phải hoàn thành ngay lập tức để trải nghiệm người dùng được tốt hơn. Sử dụng để update UI, xử lý event, việc nhẹ với độ trễ thấp. Tổng lượng công việc được làm trong class này trong quá trình thực thi của app nên nhỏ. Nó nên được chạy trên main thread.
let background = DispatchQueue.global(qos: .background)
let utility = DispatchQueue.global(qos: .utility)
let userInitiated = DispatchQueue.global(qos: .userInitiated)
let userInteractive = DispatchQueue.global(qos: .userInteractive)

3. Synchronous vs. Asynchronous

Khi queues được tạo ra xong, thì chúng ta có thể chạy code với nó, dùng kiểu đồng bộ (synchronously) thì gọi sync, dùng kiểu bất đồng bộ(asynchronously) thì gọi là async.

//Run playground
let queue = DispatchQueue(label: "queue")
queue.sync {
    for i in 0..<5 {
        print("number_A: ", i)
    }
}
queue.async {
    for i in 10..<15 {
        print("number_B: ", i)
    }
}
for i in 20..<25 {
    print("number_C: ", i)
}
//results
number_A:  0
number_A:  1
number_A:  2
number_A:  3
number_A:  4
number_B:  10
number_B:  11
number_B:  12
number_C:  20
number_B:  13
number_C:  21
number_B:  14
number_C:  22
number_C:  23
number_C:  24

Nhìn đoạn code trên ta rút ra được những thứ như sau: Vòng lặp for(20 -> 25) chạy trên main thread, trước nó sẽ có 2 tác vụ chạy sync và async. Ta thấy được tác vụ trong sync được ưu tiên chạy trước nhất, chạy hoàn thành các tasks của sync rồi mới đến 2 cái async và main thread bên dưới. Còn lại cái task là async và for, thì chương trình sẽ không đợi những tasks trong async hoàn thành mà nó thực thi song song với vòng lặp for trong main thread

Đây chỉ là ví dụ cơ bản nhất của sync, async. Với việc có thêm Quality of Service thì việc sử dụng các queues trở nên rất đa dạng và nhiều tuỳ chọn hơn cho các Developers. Phần này chỉ là giới thiệu về GDC với cú pháp và tên gọi mới. Phần sau, mình sẽ trình bày thật kỹ về Quality of Service này và các class quan trọng của Dispatch như là DispatchGroup, DispatchSemaphore,... và ứng dụng thực tế. Cảm ơn mọi người.

0