信號量
之前遇到一個問題鸵熟,一個請求需要在另一個請求獲得的參數(shù)干花。這個時候最開始的辦法是把第二個請求寫在第一個請求的回調(diào)里,但是這樣的話唆鸡,兩個請求就很緊密的耦合在一起了。這個時候可以使用信號量
來使他們分離開來枣察。
先看下相關(guān)的3個方法:
dispatch_semaphore_t dispatch_semaphore_create(long value):
方法接收一個long類型的參數(shù), 返回一個dispatch_semaphore_t
類型的信號量争占,值為傳入的參數(shù)
long dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout):
接收一個信號和時間值,若信號的信號量為0序目,則會阻塞當(dāng)前線程臂痕,直到信號量大于0或者經(jīng)過輸入的時間值;若信號量大于0猿涨,則會使信號量減1并返回握童,程序繼續(xù)住下執(zhí)行
long dispatch_semaphore_signal(dispatch_semaphore_t dsema):
使信號量加1并返回
下面看幾種使用方法
保持線程同步
let semaphore = DispatchSemaphore.init(value: 0)
var i = 10
DispatchQueue.global().async {
i = 100
semaphore.signal()
}
semaphore.wait()
print("i = \(i)")
輸出i = 100
如果注掉semaphore.wait()
這一行,則 i = 10
注釋: 由于是將block
異步添加到一個并行隊列里面嘿辟,所以程序在主線程躍過block
直接到semaphore.wait()
這一行舆瘪,因為semaphore
信號量為0
,所以當(dāng)前線程會一直阻塞红伦,直到block
在子線程執(zhí)行到semaphore.signal()
英古,使信號量+1
,此時semaphore
信號量為1
了昙读,所以程序繼續(xù)往下執(zhí)行召调。這就保證了線程間同步了。
為線程加鎖(同時可以控制最大并發(fā)數(shù)量 , value 的值等于幾就是最多幾個并發(fā))
let semaphore = DispatchSemaphore.init(value: 1)
for i in 0..<100 {
DispatchQueue.global().async {
semaphore.wait()
print("i = \(i)")
semaphore.signal()
}
}
注釋:當(dāng)線程1執(zhí)行到semaphore.wait()
這一行時蛮浑,semaphore
的信號量為1
唠叛,所以使信號量-1
變?yōu)?code>0,并且線程1
繼續(xù)往下執(zhí)行沮稚;如果當(dāng)在線程1
的print
這一行代碼還沒執(zhí)行完的時候艺沼,又有線程2來訪問,執(zhí)行semaphore.wait()
時由于此時信號量為0
(.wait()方法默認(rèn)時間是 OC 的DISPATCH_TIME_FOREVER
)蕴掏,所以會一直阻塞線程2(此時線程2處于等待狀態(tài))障般,直到線程1執(zhí)行完print
并執(zhí)行完semaphore.signal()
使信號量為1后调鲸,線程2
才能解除阻塞繼續(xù)住下執(zhí)行。以上可以保證同時只有一個線程執(zhí)行print
這一行代碼挽荡。
柵欄函數(shù)(barrier)
等待異步執(zhí)行多個任務(wù)后, 再執(zhí)行下一個任務(wù)藐石,一般使用barrier函數(shù)
//創(chuàng)建串行隊列
// let queue = DispatchQueue.init(label: "test", qos: .default, attributes: .init(rawValue: 0), autoreleaseFrequency: .workItem, target: nil)
//創(chuàng)建并行隊列
let queue = DispatchQueue.init(label: "test", qos: .default, attributes: .concurrent, autoreleaseFrequency: .workItem, target: nil)
queue.async {//任務(wù)一
for _ in 0...3 {
print("......")
}
}
queue.async {//任務(wù)二
for _ in 0...3 {
print("++++++");
}
}
queue.async(group: nil, qos: .default, flags: .barrier) {
print("group")
}
queue.async {
print("finish")
}
最后打印
......
++++++
++++++
++++++
++++++
......
......
......
group
finish
注釋:使用barrier
函數(shù)可以做到先讓前面的任務(wù)執(zhí)行完畢,再執(zhí)行之后的任務(wù)定拟,會阻塞當(dāng)前的線程
延時任務(wù)
let queue = DispatchQueue.init(label: "test", qos: .default, attributes: .concurrent, autoreleaseFrequency: .workItem, target: nil)
queue.async {//任務(wù)一
for _ in 0...3 {
print("......")
}
}
print("0")
queue.asyncAfter(deadline: DispatchTime.now() + 10, execute: {
print("延時提交的任務(wù)")
})
queue.async {//任務(wù)二
for _ in 0...3 {
print("++++++");
}
}
打佑谖ⅰ:
注釋:10s
后提交。并且不會阻礙當(dāng)前線程
組的用法(Group)
notify(依賴任務(wù))
let queue = DispatchQueue.init(label: "test", qos: .default, attributes: .concurrent, autoreleaseFrequency: .workItem, target: nil)
let group = DispatchGroup()
queue.async(group: group, qos: .default, flags: [], execute: {
for _ in 0...10 {
print("耗時任務(wù)1")
}
})
queue.async(group: group, qos: .default, flags: [], execute: {
for _ in 0...10 {
print("耗時任務(wù)2")
}
})
//執(zhí)行完上面的兩個耗時操作, 回到myQueue隊列中執(zhí)行下一步的任務(wù)
group.notify(queue: queue) {
print("回到該隊列中執(zhí)行")
}
queue.async {
print("完成")
}
打忧嘧浴:
耗時任務(wù)2
完成
耗時任務(wù)1
耗時任務(wù)2
耗時任務(wù)2
耗時任務(wù)2
耗時任務(wù)2
耗時任務(wù)1
耗時任務(wù)2
耗時任務(wù)1
耗時任務(wù)1
耗時任務(wù)1
耗時任務(wù)1
回到該隊列中執(zhí)行
注釋:使用group
+notify
的話株依,也會等待之前的任務(wù)先執(zhí)行完,和barrier
的區(qū)別是不會阻礙當(dāng)前的線程
wait(等待任務(wù))
let queue = DispatchQueue.init(label: "test", qos: .default, attributes: .concurrent, autoreleaseFrequency: .workItem, target: nil)
let group = DispatchGroup()
queue.async(group: group, qos: .default, flags: [], execute: {
for _ in 0...5 {
print("耗時任務(wù)1")
}
})
queue.async(group: group, qos: .default, flags: [], execute: {
for _ in 0...5 {
print("耗時任務(wù)2")
}
})
//等待上面任務(wù)執(zhí)行性穿,會阻塞當(dāng)前線程勺三,超時就執(zhí)行下面的,上面的繼續(xù)執(zhí)行需曾。可以無限等待 .distantFuture
let result = group.wait(timeout: .now() + 2.0)
switch result {
case .success:
print("不超時, 上面的兩個任務(wù)都執(zhí)行完")
case .timedOut:
print("超時了, 上面的任務(wù)還沒執(zhí)行完執(zhí)行這了")
}
print("接下來的操作")
打悠碓丁:
耗時任務(wù)1
耗時任務(wù)2
耗時任務(wù)1
耗時任務(wù)2
耗時任務(wù)1
耗時任務(wù)2
耗時任務(wù)1
耗時任務(wù)2
耗時任務(wù)1
耗時任務(wù)2
耗時任務(wù)1
耗時任務(wù)2
不超時, 上面的兩個任務(wù)都執(zhí)行完
接下來的操作
注釋:使用wait
+group
的話呆万,如果設(shè)置timeout = .distantFuture
的話,那么就和barrier
函數(shù)一樣了车份,會等待之前的完成谋减,否則就是等待之前的完成或者等待設(shè)置的時間到了,就會執(zhí)行接下來的任務(wù)了扫沼,會阻塞當(dāng)前現(xiàn)場出爹。