Với Swift 5.1, Grand Central Dispatch cung cấp nhiều cách để giải quyết vấn đề của bạn. Theo nhu cầu của bạn, bạn có thể chọn một trong bảy mẫu được hiển thị trong các đoạn Playground sau.
Hướng dẫn lập trình đồng thời dành cho nhà phát triển của Apple nêu vềDispatchGroup
:
Các nhóm điều phối là một cách để chặn một luồng cho đến khi một hoặc nhiều tác vụ hoàn thành thực thi. Bạn có thể sử dụng hành vi này ở những nơi bạn không thể thực hiện tiến trình cho đến khi tất cả các nhiệm vụ được chỉ định hoàn tất. Ví dụ: sau khi gửi một số tác vụ để tính toán một số dữ liệu, bạn có thể sử dụng một nhóm để chờ các tác vụ đó và sau đó xử lý kết quả khi chúng được thực hiện.
import Foundation
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
let queue = DispatchQueue(label: "com.company.app.queue", attributes: .concurrent)
let group = DispatchGroup()
queue.async(group: group) {
print("#1 started")
Thread.sleep(forTimeInterval: 5)
print("#1 finished")
}
queue.async(group: group) {
print("#2 started")
Thread.sleep(forTimeInterval: 2)
print("#2 finished")
}
group.notify(queue: queue) {
print("#3 finished")
}
/*
prints:
#1 started
#2 started
#2 finished
#1 finished
#3 finished
*/
import Foundation
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
let queue = DispatchQueue(label: "com.company.app.queue", attributes: .concurrent)
let group = DispatchGroup()
group.enter()
queue.async {
print("#1 started")
Thread.sleep(forTimeInterval: 5)
print("#1 finished")
group.leave()
}
group.enter()
queue.async {
print("#2 started")
Thread.sleep(forTimeInterval: 2)
print("#2 finished")
group.leave()
}
queue.async {
group.wait()
print("#3 finished")
}
/*
prints:
#1 started
#2 started
#2 finished
#1 finished
#3 finished
*/
Lưu ý rằng bạn cũng có thể trộn DispatchGroup
wait()
với DispatchQueue
async(group:qos:flags:execute:)
hoặc trộn DispatchGroup
enter()
và DispatchGroup
leave()
với DispatchGroup
notify(qos:flags:queue:execute:)
.
Hướng dẫn về công văn Grand Central cho Swift 4: Phần 1/2 bài viết từ Raywenderlich.com đưa ra định nghĩa cho các rào cản :
Rào cản công văn là một nhóm các chức năng hoạt động như một nút cổ chai kiểu nối tiếp khi làm việc với các hàng đợi đồng thời. Khi bạn gửi một DispatchWorkItem
hàng đợi công văn, bạn có thể đặt cờ để chỉ ra rằng đó phải là mục duy nhất được thực thi trên hàng đợi đã chỉ định cho thời gian cụ thể đó. Điều này có nghĩa là tất cả các mục được gửi đến hàng đợi trước hàng rào công văn phải hoàn thành trước khi DispatchWorkItem
thực hiện.
Sử dụng:
import Foundation
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
let queue = DispatchQueue(label: "com.company.app.queue", attributes: .concurrent)
queue.async {
print("#1 started")
Thread.sleep(forTimeInterval: 5)
print("#1 finished")
}
queue.async {
print("#2 started")
Thread.sleep(forTimeInterval: 2)
print("#2 finished")
}
queue.async(flags: .barrier) {
print("#3 finished")
}
/*
prints:
#1 started
#2 started
#2 finished
#1 finished
#3 finished
*/
import Foundation
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
let queue = DispatchQueue(label: "com.company.app.queue", attributes: .concurrent)
queue.async {
print("#1 started")
Thread.sleep(forTimeInterval: 5)
print("#1 finished")
}
queue.async {
print("#2 started")
Thread.sleep(forTimeInterval: 2)
print("#2 finished")
}
let dispatchWorkItem = DispatchWorkItem(qos: .default, flags: .barrier) {
print("#3 finished")
}
queue.async(execute: dispatchWorkItem)
/*
prints:
#1 started
#2 started
#2 finished
#1 finished
#3 finished
*/
Soroush Khanlou đã viết những dòng sau trong bài viết trên blog của Sổ tay GCD :
Sử dụng một semaphore, chúng ta có thể chặn một luồng trong một khoảng thời gian tùy ý, cho đến khi tín hiệu từ một luồng khác được gửi. Semaphores, giống như phần còn lại của GCD, an toàn cho chuỗi và chúng có thể được kích hoạt từ bất cứ đâu. Semaphores có thể được sử dụng khi có API không đồng bộ mà bạn cần tạo đồng bộ, nhưng bạn không thể sửa đổi nó.
Tham khảo API dành cho nhà phát triển của Apple cũng đưa ra các cuộc thảo luận sau cho trình DispatchSemaphore
init(value:)
khởi tạo:
Vượt qua 0 cho giá trị là hữu ích khi hai luồng cần điều hòa việc hoàn thành một sự kiện cụ thể. Truyền một giá trị lớn hơn 0 rất hữu ích để quản lý nhóm tài nguyên hữu hạn, trong đó kích thước nhóm bằng với giá trị.
Sử dụng:
import Foundation
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
let queue = DispatchQueue(label: "com.company.app.queue", attributes: .concurrent)
let semaphore = DispatchSemaphore(value: 0)
queue.async {
print("#1 started")
Thread.sleep(forTimeInterval: 5)
print("#1 finished")
semaphore.signal()
}
queue.async {
print("#2 started")
Thread.sleep(forTimeInterval: 2)
print("#2 finished")
semaphore.signal()
}
queue.async {
semaphore.wait()
semaphore.wait()
print("#3 finished")
}
/*
prints:
#1 started
#2 started
#2 finished
#1 finished
#3 finished
*/
Tham chiếu API dành cho nhà phát triển của Apple nêu về OperationQueue
:
Hàng đợi hoạt động sử dụng libdispatch
thư viện (còn được gọi là Grand Central Dispatch) để bắt đầu thực hiện các hoạt động của họ.
Sử dụng:
import Foundation
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
let operationQueue = OperationQueue()
let blockOne = BlockOperation {
print("#1 started")
Thread.sleep(forTimeInterval: 5)
print("#1 finished")
}
let blockTwo = BlockOperation {
print("#2 started")
Thread.sleep(forTimeInterval: 2)
print("#2 finished")
}
let blockThree = BlockOperation {
print("#3 finished")
}
blockThree.addDependency(blockOne)
blockThree.addDependency(blockTwo)
operationQueue.addOperations([blockThree, blockTwo, blockOne], waitUntilFinished: false)
/*
prints:
#1 started
#2 started
#2 finished
#1 finished
#3 finished
or
#2 started
#1 started
#2 finished
#1 finished
#3 finished
*/
import Foundation
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
let operationQueue = OperationQueue()
let blockOne = BlockOperation {
print("#1 started")
Thread.sleep(forTimeInterval: 5)
print("#1 finished")
}
let blockTwo = BlockOperation {
print("#2 started")
Thread.sleep(forTimeInterval: 2)
print("#2 finished")
}
operationQueue.addOperations([blockTwo, blockOne], waitUntilFinished: false)
operationQueue.addBarrierBlock {
print("#3 finished")
}
/*
prints:
#1 started
#2 started
#2 finished
#1 finished
#3 finished
or
#2 started
#1 started
#2 finished
#1 finished
#3 finished
*/