iOS Concurrency - Phần 3.5: Grand Central Dispatch

Dispatch Work Item

Dispatch Work Item là một block code mà chúng ta có thể gửi (dispatch) chúng lên bất kì queue nào. Điều này có nghĩa là chúng có thể chạy trên global queue hoặc main queue. Nếu suy nghĩ một cách đơn giản thì chúng chỉ là một đống code mà chúng ta chỉ cần gọi (invoke).

Để sử dụng Dispatch Work Item, chúng ta khởi tạo nó một instance sử dụng block và có thể chạy nó ở thread hiện tại (current thread) hay submit nó tới một Dispatch Queue.

let dwi = DispatchWorkItem {
  for i in 1...5 {
    print("DispatchWorkItem \(i)")
  }
}
//perform on the current thread
dwi.perform() //1

(//1) chúng ta sử dụng object dwi bằng cách gọi method perform(). Ở đoạn code (//1) chúng ta đang gọi nó trên thread hiện hành (main thread). Tuy nhiên chúng ta có thể sử dụng global queue để chạy như sau:

let queue = DispatchQueue.global()
queue.async {
  dwi.perform()
}

Bên cạnh đó lớp DispatchQueue cung cấp một method ngắn gọn và tiện lơi hơn mà bạn có thể thay thế method trên:

queue.async(execute: dwi)

Một Dispatch Work Item có một lá cờ cancel. Nếu Dispatch Work Item đó được cancel trước khi chạy, Dispatch Queue sẽ không chạy nó. Nhưng nếu chúng ta muốn cancel nó tại một thời điểm khi nó đang chạy, chúng ta sẽ sử dụng lá cờ cancel này. Thuộc tính cancel sẽ trả về true khi chúng ta cancel một Dispatch Work Item đang chạy. Từ đó chúng ta sử dụng thuộc tính này để break luồng chạy. Để dễ hình dung chúng ta cùng tham khảo ví dụ dưới đây:

//create the dispatch work item
var dwi:DispatchWorkItem?
dwi = DispatchWorkItem { //1
  for i in 1...5 {
    print("\(dwi?.isCancelled)")
    if (dwi?.isCancelled)!{
      break
    }
    sleep(1)
    print("DispatchWorkItem : \(i)")
  }
}
//submit the work item to the default global queue
DispatchQueue.global().async(execute: dwi!) //2
    
//cancelling the task after 3 seconds
DispatchQueue.global().async{ //3
  sleep(3)
  dwi?.cancel()
}

(//1) chúng ta khởi tạo 1 Dispatch Work Item. Ta cho vòng for chạy từ 1 tới 5.Ở mỗi lần chạy chúng ta sẽ in ra xem Dispatch Work Item hiện tại có bị gọi cancel không. Nếu nó bị gọi cancel, chúng ta sẽ break và thoát khỏi vòng for. Mỗi vòng for chúng ta sẽ cho sleep trong vòng 1 giây và in ra thứ tự của Dispatch Work Item đang chạy. (//2) Chúng ta submit Dispatch Work Item tren tới global queue. (//3) Sau 3s kể từ khi chương trình chạy, chúng ta sẽ dùng method cancel() để dừng dipatch work item. Sau khi chạy đoạn code trên chúng ta được kết quả như mong muốn.

Optional(false)
DispatchWorkItem: 1
Optional(false)
DispatchWorkItem: 2
Optional(false)
DispatchWorkItem: 3
Optional(true)

Tương tự như Dispatch Group mà mình đã nói ở bài trước, Dispatch Work Item cho phép chúng ta gọi một task khác khi một Dispatch Work Item hoàn thành bằng method notify.

let dwi = DispatchWorkItem {
  print("first task")
}

dwi.notify(queue: DispatchQueue.main) {
  print("second task")
}
DispatchQueue.global().async(execute: dwi)

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 đã biết một số kỹ thuật liên quan đến Dispatch Work Item. Ở bài tiếp theo mình sẽ giới thiệu về bộ api thứ 2 trong thế giới concurrency của Apple đó chính là: Operation và OperationQueue. Mình sẽ trình bày cách sử dụng Operation và OperationQueue để giải quyết một vấn đề mà chắc hẳn ai cũng gặp phải. Hẹn gặp các bạn ở những bài viết kế tiếp trong chuỗi series về iOS concurrency.

Tham khảo

https://medium.com/@yostane/swift-sweet-bits-the-dispatch-framework-ios-10-e34451d59a86 http://www.appcoda.com/grand-central-dispatch/