信号量
定义
1、信号量是一种可用来控制访问资源的数量的标识,设定了一个信号量,在线程访问之前,加上信号量的处理,则可告知系统按照我们指定的信号量数量来执行多个线程。
2、信号量主要的 3 个函数:
// 创建信号量,参数:信号量的初值,如果小于 0 则会返回 NULL
dispatch_semaphore_create(信号量值)
// 等待降低信号量
dispatch_semaphore_wait(信号量,等待时间)
// 提高信号量
dispatch_semaphore_signal(信号量)
正常使用顺序是先降低然后再提高,这两个函数通常成对使用。
示例 1:
/// 信号量,semaphore.wait 会阻塞线程,所以最好放在 .async 中执行,否则会阻塞后续 UI 等任务的执行,造成卡顿。
func dispatchSignal() {
let semaphore = DispatchSemaphore(value: 1)
let queue = DispatchQueue.global(qos: .default)
queue.async {
print("--->wait 1")
_ = semaphore.wait(timeout: .distantFuture)
print("--->run task 1")
sleep(1)
print("--->complete task 1")
semaphore.signal()
print("--->wait 4")
_ = semaphore.wait(timeout: .distantFuture)
print("--->run task 4")
sleep(1)
print("--->complete task 4")
semaphore.signal()
}
queue.async {
print("--->wait 2")
_ = semaphore.wait(timeout: .distantFuture)
print("--->run task 2")
sleep(3)
print("--->complete task 2")
semaphore.signal()
}
queue.async {
print("--->wait 3")
_ = semaphore.wait(timeout: .distantFuture)
print("--->run task 3")
sleep(3)
print("--->complete task 3")
semaphore.signal()
}
print("===============")
}
// 输出:
===============
--->wait 2
--->wait 1
--->wait 3
--->run task 2
--->complete task 2
--->run task 1
--->complete task 1
--->wait 4
--->run task 3
--->complete task 3
--->run task 4
--->complete task 4
// 注意:wait1、wait2、wait3 和 === 的输出顺序每次不是固定的。
示例 2:
override func viewDidLoad() {
super.viewDidLoad()
let semaphore = DispatchSemaphore(value: 0)
test1(semaphore: semaphore)
test2(semaphore: semaphore)
}
func test1(semaphore: DispatchSemaphore) {
let queue = DispatchQueue.global(qos: .default)
queue.async {
print("--->test1_1")
_ = semaphore.wait(timeout: .distantFuture)
print("--->test1_2")
semaphore.signal()
print("--->test1_3")
}
}
func test2(semaphore: DispatchSemaphore) {
print("--->test2_1")
// _ = semaphore.wait(timeout: .distantFuture)
print("--->test2")
}
输出:
--->test2_1
--->test2
--->test1_1
// 注意:由于 semaphore 初始化时设置的值为 0,在 test1 方法中执行了 .wait 方法后,信号量值小于 0,造成该线程卡死,后续方法不再执行。
示例 3:
/// 使用信号量无序调用接口
func callApiSignal2() {
let semaphore = DispatchSemaphore(value: 0)
let queue = DispatchQueue.global()
queue.async {
print("--->callApiSignal2--run task 1")
sleep(3)
print("--->callApiSignal2--complete task 1")
semaphore.signal()
}
queue.async {
print("--->callApiSignal2--run task 2")
sleep(1)
print("--->callApiSignal2--complete task 2")
semaphore.signal()
}
queue.async {
print("--->callApiSignal2--run task 3")
sleep(4)
print("--->callApiSignal2--complete task 3")
semaphore.signal()
}
print("--->callApiSignal2--wait 01")
_ = semaphore.wait(timeout: .distantFuture)
print("--->callApiSignal2--wait 02")
_ = semaphore.wait(timeout: .distantFuture)
print("--->callApiSignal2--wait 03")
_ = semaphore.wait(timeout: .distantFuture)
print("--->callApiSignal2--refresh UI")
}
// 注意:由于 semaphore 信号量初始化时设定值为 0,当程序执行到主线程的第一个 .wait 方法时,主线程被阻塞了,该线程后续方法不再执行,但不影响上面几个异步线程的执行。
当某个异步线程中模拟接口调用执行完毕,会执行 semaphore.signal(),从而将信号量值 +1,主线程中对应第一个 .wait 方法收到后线程阻塞被解除,从而会执行后续方法(打印wait 02)。
输出:
--->callApiSignal2--wait 01
--->callApiSignal2--run task 1
--->callApiSignal2--run task 2
--->callApiSignal2--run task 3
--->callApiSignal2--complete task 2
--->callApiSignal2--wait 02
--->callApiSignal2--complete task 1
--->callApiSignal2--wait 03
--->callApiSignal2--complete task 3
--->callApiSignal2--refresh UI
示例 4:
/// 使用信号量有序调用接口
func callApiSignal1() {
let semaphore = DispatchSemaphore(value: 0)
let queue = DispatchQueue.global()
queue.async {
print("--->callApiSignal1--run task 1")
sleep(3)
print("--->callApiSignal1--complete task 1")
semaphore.signal()
}
print("--->callApiSignal1--wait 01")
_ = semaphore.wait(timeout: .distantFuture)
queue.async {
print("--->callApiSignal1--run task 2")
sleep(1)
print("--->callApiSignal1--complete task 2")
semaphore.signal()
}
print("--->callApiSignal1--wait 02")
_ = semaphore.wait(timeout: .distantFuture)
queue.async {
print("--->callApiSignal1--run task 3")
sleep(4)
print("--->callApiSignal1--complete task 3")
semaphore.signal()
}
print("--->callApiSignal1--wait 03")
_ = semaphore.wait(timeout: .distantFuture)
print("--->callApiSignal1--refresh UI")
}
输出:
--->callApiSignal1--wait 01
--->callApiSignal1--run task 1
--->callApiSignal1--complete task 1
--->callApiSignal1--wait 02
--->callApiSignal1--run task 2
--->callApiSignal1--complete task 2
--->callApiSignal1--wait 03
--->callApiSignal1--run task 3
--->callApiSignal1--complete task 3
--->callApiSignal1--refresh UI
GCD Group 队列组
示例 1:group 无序调用
/// 使用 group 无序调用,闭包里是同步方法,可以不使用enter、leave方法
func callApiGroup1() {
let group = DispatchGroup()
let queue = DispatchQueue.global()
queue.async(group: group, execute: {
print("--->callApiGroup1--run task1")
})
queue.async(group: group, execute: {
print("--->callApiGroup1--run task2")
})
queue.async(group: group, execute: {
print("--->callApiGroup1--run task3")
})
group.notify(queue: queue) {
print("--->callApiGroup1--notify--run complete")
}
queue.async(group: group, execute: {
print("--->callApiGroup1--run task4")
})
}
--->callApiGroup1--run task1
--->callApiGroup1--run task4
--->callApiGroup1--run task2
--->callApiGroup1--run task3
--->callApiGroup1--notify--run complete
示例 2:group 无序调用接口进阶版
/// 使用 group 无序调用接口进阶版,闭包里是异步方法,需要使用enter、leave方法
func callApiGroup2() {
let group = DispatchGroup()
let queue = DispatchQueue.global()
queue.async(group: group, execute: {
group.enter()
// 模拟网络请求
queue.asyncAfter(deadline: .now() + 4) {
print("--->callApiGroup2--run task1")
// 通知 group,任务成功完成,要移除,与 enter 成对出现。
group.leave()
}
})
queue.async(group: group, execute: {
group.enter()
// 模拟网络请求
queue.asyncAfter(deadline: .now() + 1) {
print("--->callApiGroup2--run task2")
// 通知 group,任务成功完成,要移除,与 enter 成对出现。
group.leave()
}
})
queue.async(group: group, execute: {
group.enter()
// 模拟网络请求
queue.asyncAfter(deadline: .now() + 6) {
print("--->callApiGroup2--run task3")
// 通知 group,任务成功完成,要移除,与 enter 成对出现。
group.leave()
}
})
queue.async(group: group, execute: {
group.enter()
// 模拟网络请求
queue.asyncAfter(deadline: .now() + 10) {
print("--->callApiGroup2--run task4")
// 通知 group,任务成功完成,要移除,与 enter 成对出现。
group.leave()
}
})
queue.async(group: group, execute: {
group.enter()
print("--->callApiGroup2--run task5")
group.leave()
})
group.notify(queue: queue) {
print("--->callApiGroup2--notify--run complete")
}
}
输出:
--->callApiGroup2--run task5
--->callApiGroup2--run task2
--->callApiGroup2--run task1
--->callApiGroup2--run task3
--->callApiGroup2--run task4
--->callApiGroup2--notify--run complete
网友评论