- pThread幾乎不用寝蹈,不用管
- NSThread
NSThread是對(duì)pThread的封裝
優(yōu)點(diǎn):
1.實(shí)時(shí)性更高
2.與RunLoop結(jié)合,提供更為靈活高效的線程管理方式
缺點(diǎn):
1.創(chuàng)建線程代時(shí)班套,需要同時(shí)占用應(yīng)用和內(nèi)核的內(nèi)2.存空間(GCD只占用內(nèi)核的內(nèi)存空間)
編寫線程相關(guān)代碼相對(duì)繁雜
線程的創(chuàng)建方式
[NSThread detachNewThreadWithBlock:^{
NSLog(@"NSThread");
}];
// 2.
[NSThread detachNewThreadSelector:@selector(dosomething:) toTarget:self withObject:data];
// 3.
NSThread * thread = [[NSThread alloc]initWithTarget:self selector:@selector(dosomething:) object:data];
thread.name = @"thread1";
[thread start];
- GCD
項(xiàng)目中使用dispatch_async處理證件信息修改對(duì)OCR識(shí)別到大圖片壓縮耗時(shí)操作,壓縮完成后去請(qǐng)求接口蹦浦,JJ的做任務(wù)下載用了dispatch_group_t,還有JJ的檢測(cè)最優(yōu)線路也用了dispatch_group_t等
dispatch_sync同步
dispatch_async異步任務(wù)派發(fā)
dispatch_queue_t串行隊(duì)列與并發(fā)隊(duì)列
dispatch_once_t只執(zhí)行一次
dispatch_after延后執(zhí)行
dispatch_group_t組調(diào)度
dispatch_barrier_(a)sync柵欄
dispatch_semaphore信號(hào)量
dispatch_semaphore 是信號(hào)量模孩,但當(dāng)信號(hào)總量設(shè)為 1 時(shí)也可以當(dāng)作鎖來(lái)琳要。在沒有等待情況出現(xiàn)時(shí)衫嵌,它的性能比 pthread_mutex(自旋鎖) 還要高,但一旦有等待情況出現(xiàn)時(shí)砂心,性能就會(huì)下降許多懈词。相對(duì)于 OSSpinLock 來(lái)說,它的優(yōu)勢(shì)在于等待時(shí)不會(huì)消耗 CPU 資源辩诞。對(duì)磁盤緩存來(lái)說坎弯,它比較合適。自旋鎖更適合內(nèi)存緩存,雖然占用一些CPU荞怒,但是快
//可設(shè)置最大并發(fā)數(shù)洒琢,目前最大并發(fā)數(shù)為5,設(shè)置最大并發(fā)數(shù)還是建議用NSOperation
dispatch_semaphore_t sem = dispatch_semaphore_create(5);
//最大并發(fā)為1時(shí)也可以當(dāng)鎖使用
dispatch_semaphore_t sem = dispatch_semaphore_create(1);
dispatch_async(dispatch_get_global_queue(0, 0), ^{
執(zhí)行耗時(shí)操作};
dispatch_async(dispatch_get_main_queue(), ^{
回到主線程進(jìn)行UI刷新操作
};
GCD中dispatch_queue大致可以分為三類
全局的并行的queue
主線程的串行的queue
自定義的queue
全局的queue和主線程的queue結(jié)合使用(上邊提到的)就是我們平常最常用的一種用法褐桌,在異步線程中執(zhí)行耗時(shí)操作衰抑,然后在UI線程執(zhí)行刷新操作。
全局的queue我們可以通過dispatch_get_global_queue(0, 0)直接獲取荧嵌,這里有兩個(gè)參數(shù)呛踊,第一個(gè)表示線程執(zhí)行的優(yōu)先級(jí)(第二個(gè)參數(shù)是預(yù)留參數(shù)暫時(shí)沒用)
第一個(gè)參數(shù)有以下幾個(gè)狀態(tài)
DISPATCH_QUEUE_PRIORITY_HIGH 2
-》DISPATCH_QUEUE_PRIORITY_DEFAULT 0
-》DISPATCH_QUEUE_PRIORITY_LOW (-2)
-》DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN,具體打印結(jié)果看下面內(nèi)容
下面我們?cè)O(shè)置第一個(gè)參數(shù)默認(rèn)值為0
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"start task 1");
[NSThread sleepForTimeInterval:3];
NSLog(@"end task 1");
});
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"start task 2");
[NSThread sleepForTimeInterval:3];
NSLog(@"end task 2");
});
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"start task 3");
[NSThread sleepForTimeInterval:3];
NSLog(@"end task 3");
});
輸出結(jié)果
2021-03-16 15:49:52.344146+0800 TestDemo[54759:1269344] start task 2
2021-03-16 15:49:52.344151+0800 TestDemo[54759:1269347] start task 3
2021-03-16 15:49:52.344146+0800 TestDemo[54759:1269346] start task 1
2021-03-16 15:49:55.348151+0800 TestDemo[54759:1269346] end task 1
2021-03-16 15:49:55.348151+0800 TestDemo[54759:1269347] end task 3
2021-03-16 15:49:55.348218+0800 TestDemo[54759:1269344] end task 2
下面設(shè)置優(yōu)先級(jí)
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
NSLog(@"start task 0");
[NSThread sleepForTimeInterval:3];
NSLog(@"end task 0");
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
NSLog(@"start task 1");
[NSThread sleepForTimeInterval:3];
NSLog(@"end task 1");
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
NSLog(@"start task 2");
[NSThread sleepForTimeInterval:3];
NSLog(@"end task 2");
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"start task 3");
[NSThread sleepForTimeInterval:3];
NSLog(@"end task 3");
});
021-03-16 16:04:20.881211+0800 TestDemo[54815:1279607] start task 2
2021-03-16 16:04:20.881211+0800 TestDemo[54815:1279609] start task 3
2021-03-16 16:04:20.922642+0800 TestDemo[54815:1279608] start task 1
2021-03-16 16:04:21.037538+0800 TestDemo[54815:1279606] start task 0
2021-03-16 16:04:23.882068+0800 TestDemo[54815:1279609] end task 3
2021-03-16 16:04:23.882066+0800 TestDemo[54815:1279607] end task 2
2021-03-16 16:04:24.057318+0800 TestDemo[54815:1279608] end task 1
2021-03-16 16:04:24.133597+0800 TestDemo[54815:1279606] end task 0
串行隊(duì)列和并發(fā)隊(duì)列
dispatch_queue_create(const char *label, dispatch_queue_attr_t attr),這個(gè)方法同樣也有兩個(gè)參數(shù)啦撮,第一個(gè)參數(shù)是確定唯一queue的一個(gè)標(biāo)識(shí)谭网,第二個(gè)參數(shù)創(chuàng)建queue的類型
DISPATCH_QUEUE_SERIAL(串行)
DISPATCH_QUEUE_CONCURRENT(并發(fā))
dispatch_queue_t myQueue = dispatch_queue_create("testQueue", DISPATCH_QUEUE_SERIAL(串行)/DISPATCH_QUEUE_CONCURRENT(并發(fā)));
dispatch_async(myQueue, ^{
NSLog(@"start task 1");
[NSThread sleepForTimeInterval:3];
NSLog(@"end task 1");
});
dispatch_async(myQueue, ^{
NSLog(@"start task 2");
[NSThread sleepForTimeInterval:3];
NSLog(@"end task 2");
});
dispatch_async(myQueue, ^{
NSLog(@"start task 3");
[NSThread sleepForTimeInterval:3];
NSLog(@"end task 3");
});
串行隊(duì)列輸出結(jié)果
2021-03-16 16:28:15.643198+0800 TestDemo[55024:1292810] start task 1
2021-03-16 16:28:18.643548+0800 TestDemo[55024:1292810] end task 1
2021-03-16 16:28:18.643854+0800 TestDemo[55024:1292810] start task 2
2021-03-16 16:28:21.648152+0800 TestDemo[55024:1292810] end task 2
2021-03-16 16:28:21.648631+0800 TestDemo[55024:1292810] start task 3
2021-03-16 16:28:24.653826+0800 TestDemo[55024:1292810] end task 3
并發(fā)隊(duì)列輸出結(jié)果
2021-03-16 16:33:54.921235+0800 TestDemo[55071:1297272] start task 2
2021-03-16 16:33:54.921235+0800 TestDemo[55071:1297270] start task 1
2021-03-16 16:33:54.921243+0800 TestDemo[55071:1297271] start task 3
2021-03-16 16:33:57.923428+0800 TestDemo[55071:1297272] end task 2
2021-03-16 16:33:57.923442+0800 TestDemo[55071:1297271] end task 3
2021-03-16 16:33:57.923442+0800 TestDemo[55071:1297270] end task 1
dipatch_group(調(diào)度組)的使用,項(xiàng)目使用JJ的多章節(jié)任務(wù)下載赃春,等所有任務(wù)下載成功后彈窗提示已完成愉择,還有就是檢測(cè)最優(yōu)線路后刷新UI
重點(diǎn):
dispatch_group_enter()(入組)
dispatch_group_leave()(出組)
- (void)test{
dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group);
[self sendRequest1:^{
dispatch_group_leave(group);
}];
dispatch_group_enter(group);
[self sendRequest2:^{
dispatch_group_leave(group);
}];
dispatch_group_notify(group, dispatch_queue_create(0, 0), ^{
NSLog(@"task over");
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"refresh ui");
});
});
}
- (void)sendRequest1:(void(^)())block {
//異步請(qǐng)求,請(qǐng)求結(jié)果后block回調(diào)
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"start task 1");
[NSThread sleepForTimeInterval:3];
NSLog(@"end task 1");
dispatch_async(dispatch_get_main_queue(), ^{
if (block) {
block();
}
});
});
}
- (void)sendRequest2:(void(^)())block {
//異步請(qǐng)求织中,請(qǐng)求結(jié)果后block回調(diào)
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"start task 2");
[NSThread sleepForTimeInterval:3];
NSLog(@"end task 2");
dispatch_async(dispatch_get_main_queue(), ^{
if (block) {
block();
}
});
});
}
輸出結(jié)果
2021-03-16 16:53:52.788430+0800 TestDemo[55332:1314700] start task 2
2021-03-16 16:53:52.788430+0800 TestDemo[55332:1314695] start task 1
2021-03-16 16:53:55.789766+0800 TestDemo[55332:1314700] end task 2
2021-03-16 16:53:55.789766+0800 TestDemo[55332:1314695] end task 1
2021-03-16 16:53:55.790373+0800 TestDemo[55332:1314695] task over
2021-03-16 16:53:55.790798+0800 TestDemo[55332:1314538] refresh ui
dispatch_once_t一次執(zhí)行锥涕,常用來(lái)實(shí)現(xiàn)單例模式,這里以單例模式實(shí)現(xiàn)的模板代碼為例展示dispatch_once_t的用法狭吼,其中的實(shí)例化語(yǔ)句只會(huì)被執(zhí)行一次:
+ (instancetype *)sharedInstance {
static dispatch_once_t once = 0;
static id sharedInstance = nil;
dispatch_once(&once, ^{
// 只實(shí)例化一次
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
dispatch_barrier_(a)sync 柵欄函數(shù)
通過Dispatch_barrier_async添加的操作會(huì)暫時(shí)阻塞當(dāng)前隊(duì)列层坠,即等待前面的并發(fā)操作都完成后執(zhí)行該阻塞操作,待其完成后后面的并發(fā)操作才可繼續(xù)刁笙∑苹ǎ可以將其比喻為一座霸道的獨(dú)木橋,是并發(fā)隊(duì)列中的一個(gè)并發(fā)障礙點(diǎn)疲吸,臨時(shí)阻塞并獨(dú)占座每。
可見使用Dispatch_barrier_async可以實(shí)現(xiàn)類似dispatch_group_t組調(diào)度的效果,同時(shí)主要的作用是避免數(shù)據(jù)競(jìng)爭(zhēng),高效訪問數(shù)據(jù)磅氨。
??官方說明大意:在使用柵欄函數(shù)時(shí).使用自定義隊(duì)列才有意義,如果用的是串行隊(duì)列或者系統(tǒng)提供的全局并發(fā)隊(duì)列,這個(gè)柵欄函數(shù)的作用等同于一個(gè)同步函數(shù)的作用
☆??關(guān)于dispatch_barrier_(a)sync區(qū)別
個(gè)人理解:dispatch_barrier_sync 需要等待柵欄執(zhí)行完才會(huì)執(zhí)行柵欄后面的任務(wù),而dispatch_barrier_async 無(wú)需等待柵欄執(zhí)行完,會(huì)繼續(xù)往下走(保留在隊(duì)列里)
/* 創(chuàng)建并發(fā)隊(duì)列 */
dispatch_queue_t concurrentQueue = dispatch_queue_create("test.concurrent.queue", DISPATCH_QUEUE_CONCURRENT);
/* 添加兩個(gè)并發(fā)操作A和B尺栖,即A和B會(huì)并發(fā)執(zhí)行 */
dispatch_async(concurrentQueue, ^(){
NSLog(@"OperationA");
});
dispatch_async(concurrentQueue, ^(){
NSLog(@"OperationB");
});
/* 添加barrier障礙操作嫡纠,會(huì)等待前面的并發(fā)操作結(jié)束烦租,并暫時(shí)阻塞后面的并發(fā)操作直到其完成 */
dispatch_barrier_async(concurrentQueue, ^(){
NSLog(@"OperationBarrier!");
});
NSLog(@"驗(yàn)證async和sync的區(qū)別--現(xiàn)在是async");
/* 繼續(xù)添加并發(fā)操作C和D,要等待barrier障礙操作結(jié)束才能開始 */
dispatch_async(concurrentQueue, ^(){
NSLog(@"OperationC");
});
dispatch_async(concurrentQueue, ^(){
NSLog(@"OperationD");
});
?? dispatch_barrier_async輸出結(jié)果
2021-03-16 17:33:09.429076+0800 TestDemo[55672:1343472] OperationB
2021-03-16 17:33:09.429084+0800 TestDemo[55672:1343332] 驗(yàn)證async和sync的區(qū)別--現(xiàn)在是async
2021-03-16 17:33:09.429090+0800 TestDemo[55672:1343476] OperationA
2021-03-16 17:33:09.429235+0800 TestDemo[55672:1343476] OperationBarrier!
2021-03-16 17:33:09.429327+0800 TestDemo[55672:1343476] OperationC
2021-03-16 17:33:09.429329+0800 TestDemo[55672:1343472] OperationD
??dispatch_barrier_sync輸出結(jié)果
2021-03-16 17:34:36.483220+0800 TestDemo[55690:1345240] OperationB
2021-03-16 17:34:36.483245+0800 TestDemo[55690:1345246] OperationA
2021-03-16 17:34:36.483487+0800 TestDemo[55690:1345114] OperationBarrier!
2021-03-16 17:34:36.483578+0800 TestDemo[55690:1345114] 驗(yàn)證async和sync的區(qū)別--現(xiàn)在是sync
2021-03-16 17:34:36.483675+0800 TestDemo[55690:1345242] OperationD
2021-03-16 17:34:36.483681+0800 TestDemo[55690:1345246] OperationC
dispatch_after
通過該函數(shù)可以讓要提交的任務(wù)在從提交開始后的指定時(shí)間后執(zhí)行除盏,也就是定時(shí)延遲執(zhí)行提交的任務(wù)叉橱,使用方法很簡(jiǎn)單:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
//延遲執(zhí)行
});
- NSOperation 和 NSOperationQueue
項(xiàng)目中的使用:例如微信分享圖片時(shí),等圖片下載完后再分享者蠕,用的NSOperationQueue
當(dāng) NSOperation 支持了 cancel 操作時(shí)窃祝,NSOperationQueue 可以使用 cancelAllOperatoins 來(lái)對(duì)所有的 operation 執(zhí)行 cancel 操作。
不過 cancel 的效果還是取決于 NSOperation 中代碼是怎么寫的踱侣。(比如 對(duì)于數(shù)據(jù)庫(kù)的某些操作線程來(lái)說粪小,cancel 可能會(huì)意味著 你需要把數(shù)據(jù)恢復(fù)到最原始的狀態(tài)大磺。)
maxConcurrentOperationCount設(shè)置最大并發(fā)數(shù)
默認(rèn)的最大并發(fā) operation 數(shù)量是由系統(tǒng)當(dāng)前的運(yùn)行情況決定的(來(lái)源),我們也可以強(qiáng)制指定一個(gè)固定的并發(fā)數(shù)量探膊。
GCD 與 NSOperation 的對(duì)比杠愧,面試中會(huì)經(jīng)常問,因?yàn)檫@兩個(gè)都很強(qiáng)大逞壁,我們也都經(jīng)常在用
- NSOperationQueue 是基于 GCD 的更高層的封裝(從 OS X 10.10 開始可以通過設(shè)置 underlyingQueue 來(lái)把 operation 放到已有的 dispatch queue 中流济。)
- 從易用性角度,GCD 由于采用 C 風(fēng)格的 API腌闯,在調(diào)用上比使用面向?qū)ο箫L(fēng)格的 NSOperation 要簡(jiǎn)單一些绳瘟。
- 從對(duì)任務(wù)的控制性來(lái)說,NSOperation 顯著得好于 GCD姿骏,和 GCD 相比支持了 Cancel 操作(注:在 iOS8 中 GCD 引入了 dispatch_block_cancel 和 dispatch_block_testcancel糖声,也可以支持 Cancel 操作了),支持任務(wù)之間的依賴關(guān)系分瘦,支持同一個(gè)隊(duì)列中任務(wù)的優(yōu)先級(jí)設(shè)置姨丈,同時(shí)還可以通過 KVO 來(lái)監(jiān)控任務(wù)的執(zhí)行情況。(這些通過 GCD 也可以實(shí)現(xiàn)擅腰,不過需要很多代碼蟋恬,使用 NSOperation 顯得方便了很多。)
- 從第三方庫(kù)的角度趁冈,知名的第三方庫(kù)如 AFNetworking 和 SDWebImage 背后都是使用 NSOperation歼争,也從另一方面說明對(duì)于需要復(fù)雜并發(fā)控制的需求,NSOperation 可能是更好的選擇渗勘,但也并不絕對(duì)沐绒,各有利弊,這只是個(gè)人理解旺坠。
NSOperation的使用
maxConcurrentOperationCount設(shè)置對(duì)大并發(fā)數(shù)
??切勿添加循環(huán)依賴
- (void)test
{
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"11111111%@", [NSThread currentThread]);
}];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"22222%@", [NSThread currentThread]);
}];
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
sleep(3);
NSLog(@"333333 %@", [NSThread currentThread]);
}];
NSBlockOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"44444444%@", [NSThread currentThread]);
}];
// 指定操作之間的”依賴“關(guān)系乔遮,某一個(gè)操作的執(zhí)行,必須等待另一個(gè)操作完成才會(huì)開始
// 依賴關(guān)系是可以跨隊(duì)列指定的
[op2 addDependency:op1];
[op3 addDependency:op2];
[op4 addDependency:op3];
// *** 添加依賴的時(shí)候取刃,注意不要出現(xiàn)循環(huán)依賴
// [op3 addDependency:op4];
[self.queue addOperation:op1];
[self.queue addOperation:op2];
[self.queue addOperation:op3];
// 主隊(duì)列更新UI
[[NSOperationQueue mainQueue] addOperation:op4];
}
- (NSOperationQueue *)queue
{
if (!_queue) _queue = [[NSOperationQueue alloc] init];
return _queue;
}