背景
擔(dān)心了兩周的我終于輪到去醫(yī)院做胃鏡檢查了!去的時(shí)候我都想好了最壞的可能(胃癌)巍举,之前在網(wǎng)上查的癥狀都很相似窜锯。最后檢查結(jié)果出來終于安心了蚌成,診斷結(jié)果:慢性非萎縮性胃炎(胃竇為主)
我是一個(gè)心里素質(zhì)不過關(guān)的人,所以說對(duì)待問題的時(shí)候可能會(huì)有一種悲觀的想法晌砾。朋友說我本來可能沒病都被自己嚇出病了坎拐,這是一個(gè)心態(tài)問題。
你們可能問我做胃鏡什么感覺养匈?我只能告訴你一個(gè)字:真爽哼勇,具體只能自己去感受。
保持樂觀的心態(tài)
看完下面的笑話就要開始我們的裝逼之旅了_
- 一個(gè)大學(xué)生去公司實(shí)習(xí)呕乎,老板讓他先從掃地開始积担。大學(xué)生:“我可是大學(xué)生哎……”老板:“哦,對(duì)了楣嘁,我差點(diǎn)忘了你是大學(xué)生磅轻,來來來珍逸,我教你怎么掃地”
- 一天,老師讓同學(xué)們寫作文聋溜,題目是 《我的理想》谆膳。
小明在作文里寫道:我長大了要去搶銀行,然后把錢分給窮苦老百姓撮躁。
第二天老師改完了漱病,寫給小明的評(píng)語是這樣的:很不錯(cuò)的理想,分錢的時(shí)候不要忘了老師把曼,但你要注意你的同桌杨帽,他說他長大了要去當(dāng)警察。
GCD基本介紹
- GCD(Grand Central Dispatch)iOS 4.0開始引入的新多線程編程功能,
- GCD(Grand Central Dispatch)是異步執(zhí)行任務(wù)的技術(shù)之一嗤军。一般將應(yīng)用程序中記述的線程管理用的代碼在系統(tǒng)級(jí)中實(shí)現(xiàn)注盈。開發(fā)者只需要定義想執(zhí)行的任務(wù)并追加到適當(dāng)?shù)腄ispatch Queue中,GCD就能生成必要的線程并計(jì)劃執(zhí)行任務(wù)叙赚。
- GCD(Grand Central Dispatch)是基于C語言開發(fā)的一套多線程開發(fā)機(jī)制老客,是完全面向過程的。
GCD基本概念
這就需要上一篇博客里的基本知識(shí)了(不清楚去看下)iOS開發(fā)之多線程編程總結(jié)(一)
任務(wù)和隊(duì)列
-
任務(wù):就是執(zhí)行操作的意思震叮,換句話說就是你在線程中執(zhí)行的那段代碼胧砰。在GCD中是放在block中的。執(zhí)行任務(wù)有兩種方式:同步執(zhí)行和異步執(zhí)行苇瓣。兩者的主要區(qū)別是:是否具備開啟新線程的能力勤揩。
- 同步執(zhí)行(sync):只能在當(dāng)前線程中執(zhí)行任務(wù)弥激,不具備開啟新線程的能力
- 必須等待當(dāng)前語句執(zhí)行完畢,才會(huì)執(zhí)行下一條語句
- 不會(huì)開啟線程
- 在當(dāng)前主線程執(zhí)行 block 的任務(wù)
dispatch_sync(queue, block);
- ** 異步執(zhí)行(async)**:可以在新的線程中執(zhí)行任務(wù),具備開啟新線程的能力
- 不用等待當(dāng)前語句執(zhí)行完畢绣的,就可以執(zhí)行下一條語句
- 會(huì)開啟線程執(zhí)行 block 的任務(wù)
- 異步是多線程的代名詞
dispatch_async(queue, block);
-
隊(duì)列:這里的隊(duì)列指任務(wù)隊(duì)列真仲,即用來存放任務(wù)的隊(duì)列益咬。隊(duì)列是一種特殊的線性表奕短,采用FIFO(先進(jìn)先出)的原則,即新任務(wù)總是被插入到隊(duì)列的末尾损话,而讀取任務(wù)的時(shí)候總是從隊(duì)列的頭部開始讀取侦啸。每讀取一個(gè)任務(wù),則從隊(duì)列中釋放一個(gè)任務(wù)丧枪。在GCD中有四種隊(duì)列:串行隊(duì)列光涂、并發(fā)隊(duì)列、主隊(duì)列拧烦、全局隊(duì)列忘闻。
-
串行隊(duì)列(Serial Dispatch Queue):讓任務(wù)一個(gè)接著一個(gè)地執(zhí)行(一個(gè)任務(wù)執(zhí)行完畢后,再執(zhí)行下一個(gè)任務(wù))
- 一次只能"調(diào)度"一個(gè)任務(wù)
-
dispatch_queue_create("queue", NULL);
或者dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
-
并發(fā)隊(duì)列(Concurrent Dispatch Queue):可以讓多個(gè)任務(wù)并發(fā)(同時(shí))執(zhí)行(自動(dòng)開啟多個(gè)線程同時(shí)執(zhí)行任務(wù))恋博,
- 一次可以"調(diào)度"多個(gè)任務(wù)
- 并發(fā)功能只有在異步(dispatch_async)函數(shù)下才有效
dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
-
主隊(duì)列
- 專門用來在主線程上調(diào)度任務(wù)的隊(duì)列
- 不會(huì)開啟線程
- 在主線程空閑時(shí)才會(huì)調(diào)度隊(duì)列中的任務(wù)在主線程執(zhí)行
- dispatch_get_main_queue();
-
全局隊(duì)列
- 執(zhí)行過程和并發(fā)隊(duì)列一致齐佳,參考并發(fā)隊(duì)列
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
-
小結(jié): 在以后的使用中私恬,記住下面的就可以了!
- 開不開線程由執(zhí)行任務(wù)的函數(shù)決定
- 異步開炼吴,異步是多線程的代名詞
- 同步不開
- 開幾條線程由隊(duì)列決定
- 串行隊(duì)列開一條線程(GCD會(huì)開一條本鸣,NSOperation Queue最大并發(fā)數(shù)為1時(shí)也可能開多條)
- 并發(fā)隊(duì)列開多條線程,具體能開的線程數(shù)量由底層線程池決定
GCD的使用
今天我們學(xué)習(xí)下面圖片的相關(guān)知識(shí)點(diǎn)硅蹦,Demo下載鏈接會(huì)在文章最后給出來
簡單來看一段代碼:異步下載圖片
#pragma mark - 1.異步下載圖片
- (IBAction)downLoadAction:(UIButton *)sender {
self.imageView.image = nil;
//獲取全局隊(duì)列
dispatch_async(dispatch_get_global_queue(0, 0), ^{
//異步下載圖片
NSURL *url=[NSURL URLWithString:@"https://p1.bpimg.com/524586/475bc82ff016054ds.jpg"];
//將資源轉(zhuǎn)換為二進(jìn)制
NSData *data=[NSData dataWithContentsOfURL:url];
//將二進(jìn)制轉(zhuǎn)化為圖片
UIImage *image=[UIImage imageWithData:data];
//獲取主隊(duì)列,更新UI
dispatch_async(dispatch_get_main_queue(), ^{
//給圖片控件賦值
self.imageView.image=image;
});
});
}
和NSThread對(duì)比可以發(fā)現(xiàn)
- 所有的代碼寫在一起的荣德,讓代碼更加簡單,易于閱讀和維護(hù)
- NSThread 通過 @selector 指定要執(zhí)行的方法童芹,代碼分散
- GCD 通過 block 指定要執(zhí)行的代碼涮瞻,代碼集中
- 使用 GCD 不需要管理線程的創(chuàng)建/銷毀/復(fù)用的過程!程序員不用關(guān)心線程的生命周期
- 如果要開多個(gè)線程 NSThread 必須實(shí)例化多個(gè)線程對(duì)象或者使用分類方法
- NSThread 靠 NSObject 的分類方法實(shí)現(xiàn)的線程間通訊假褪,GCD 靠 block
-
dispatch_async(queue, block);
就是異步執(zhí)行一個(gè)隊(duì)列里面的任務(wù)block署咽。每個(gè)block之間是異步執(zhí)行的,但是block里面的代碼是順序執(zhí)行的嗜价! -
dispatch_sync(queue, block);
就是同步執(zhí)行一個(gè)隊(duì)列里面的任務(wù)block
1. 串行隊(duì)列(Serial Dispatch Queue)
串行隊(duì)列的創(chuàng)建:
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t queue = dispatch_queue_create("queue", NULL);
串行隊(duì)列同步和異步執(zhí)行Demo:
#pragma mark - 串行隊(duì)列同步和串行隊(duì)列異步
//串行隊(duì)列同步
- (void)serialQueueSyncMethod{
//創(chuàng)建隊(duì)列
dispatch_queue_t queue = dispatch_queue_create("serialQueueSyncMethod", DISPATCH_QUEUE_SERIAL);
//執(zhí)行任務(wù)
for (int i = 0; i < 6; i++) {
NSLog(@"mainThread--->%d",i);
dispatch_sync(queue, ^{
NSLog(@"Current Thread=%@---->%d-----",[NSThread currentThread],i);
});
}
NSLog(@"串行隊(duì)列同步end");
}
//串行隊(duì)列異步
- (void)serialQueueAsyncMethod{
dispatch_queue_t queue = dispatch_queue_create("serialQueueAsyncMethod", DISPATCH_QUEUE_SERIAL);
for (int i = 0; i < 6; i++) {
NSLog(@"mainThread--->%d",i);
dispatch_async(queue, ^{
NSLog(@"Current Thread=%@---->%d-----",[NSThread currentThread],i);
});
}
NSLog(@"串行隊(duì)列異步end");
}
串行隊(duì)列 同步執(zhí)行結(jié)果:
2016-11-03 17:16:35.794 ThreadDemo[27088:5268309] mainThread--->0
2016-11-03 17:16:35.795 ThreadDemo[27088:5268309] Current Thread=<NSThread: 0x60800007ae40>{number = 1, name = main}---->0-----
2016-11-03 17:16:35.795 ThreadDemo[27088:5268309] mainThread--->1
2016-11-03 17:16:35.795 ThreadDemo[27088:5268309] Current Thread=<NSThread: 0x60800007ae40>{number = 1, name = main}---->1-----
2016-11-03 17:16:35.795 ThreadDemo[27088:5268309] mainThread--->2
2016-11-03 17:16:35.795 ThreadDemo[27088:5268309] Current Thread=<NSThread: 0x60800007ae40>{number = 1, name = main}---->2-----
2016-11-03 17:16:35.795 ThreadDemo[27088:5268309] mainThread--->3
2016-11-03 17:16:35.796 ThreadDemo[27088:5268309] Current Thread=<NSThread: 0x60800007ae40>{number = 1, name = main}---->3-----
2016-11-03 17:16:35.796 ThreadDemo[27088:5268309] mainThread--->4
2016-11-03 17:16:35.796 ThreadDemo[27088:5268309] Current Thread=<NSThread: 0x60800007ae40>{number = 1, name = main}---->4-----
2016-11-03 17:16:35.796 ThreadDemo[27088:5268309] mainThread--->5
2016-11-03 17:16:35.796 ThreadDemo[27088:5268309] Current Thread=<NSThread: 0x60800007ae40>{number = 1, name = main}---->5-----
2016-11-03 17:16:35.796 ThreadDemo[27088:5268309] 串行隊(duì)列同步end
串行隊(duì)列 異步執(zhí)行結(jié)果:
2016-11-03 17:22:25.074 ThreadDemo[27122:5273206] mainThread--->0
2016-11-03 17:22:25.074 ThreadDemo[27122:5273206] mainThread--->1
2016-11-03 17:22:25.074 ThreadDemo[27122:5273252] Current Thread=<NSThread: 0x60800007f380>{number = 5, name = (null)}---->0-----
2016-11-03 17:22:25.074 ThreadDemo[27122:5273206] mainThread--->2
2016-11-03 17:22:25.074 ThreadDemo[27122:5273252] Current Thread=<NSThread: 0x60800007f380>{number = 5, name = (null)}---->1-----
2016-11-03 17:22:25.074 ThreadDemo[27122:5273206] mainThread--->3
2016-11-03 17:22:25.075 ThreadDemo[27122:5273252] Current Thread=<NSThread: 0x60800007f380>{number = 5, name = (null)}---->2-----
2016-11-03 17:22:25.075 ThreadDemo[27122:5273206] mainThread--->4
2016-11-03 17:22:25.075 ThreadDemo[27122:5273252] Current Thread=<NSThread: 0x60800007f380>{number = 5, name = (null)}---->3-----
2016-11-03 17:22:25.075 ThreadDemo[27122:5273206] mainThread--->5
2016-11-03 17:22:25.075 ThreadDemo[27122:5273252] Current Thread=<NSThread: 0x60800007f380>{number = 5, name = (null)}---->4-----
2016-11-03 17:22:25.075 ThreadDemo[27122:5273206] 串行隊(duì)列異步end
2016-11-03 17:22:25.075 ThreadDemo[27122:5273252] Current Thread=<NSThread: 0x60800007f380>{number = 5, name = (null)}---->5-----
小結(jié):
- 從串行隊(duì)列同步執(zhí)行結(jié)果看出打印是交替執(zhí)行的艇抠!從打印中看到number=1,說明線程block任務(wù)是在主線程中執(zhí)行的久锥。因?yàn)?strong>同步是不會(huì)開辟線程的,所有當(dāng)前只有一個(gè)主線程MainThread异剥。也就是說串行隊(duì)列同步執(zhí)行不會(huì)開辟線程瑟由,所有block任務(wù)之間是同步執(zhí)行的
- 從串行隊(duì)列異步執(zhí)行結(jié)果看出打印并不是交替執(zhí)行的!從打印中看到number=5冤寿,說明線程block的任務(wù)是在一個(gè)全新的線程中執(zhí)行的歹苦。因?yàn)?strong>異步是會(huì)開辟線程的,所有當(dāng)前有主線程MainThread和子線程number=5督怜。也就是說串行隊(duì)列異步執(zhí)行會(huì)僅會(huì)開辟一個(gè)新的線程殴瘦,所有block任務(wù)之間是同步執(zhí)行的
- 以先進(jìn)先出的方式,順序調(diào)度隊(duì)列中的任務(wù)執(zhí)行
- 無論隊(duì)列中指定的任務(wù)函數(shù)是同步還是異步,都會(huì)等待前一個(gè)任務(wù)執(zhí)行完畢以后,再調(diào)度后面的任務(wù)
2. 并發(fā)隊(duì)列(Concurrent Dispatch Queue)
并發(fā)隊(duì)列創(chuàng)建
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
并發(fā)隊(duì)列同步和異步執(zhí)行Demo
#pragma mark - 并行隊(duì)列同步和并行隊(duì)列異步
//并行隊(duì)列同步
- (void)concurrentQueueSyncMethod{
dispatch_queue_t queue = dispatch_queue_create("concurrentQueueSyncMethod", DISPATCH_QUEUE_CONCURRENT);
for (int i = 0; i < 6; i++) {
dispatch_sync(queue, ^{
NSLog(@"Current Thread=%@---->%d-----",[NSThread currentThread],i);
});
}
NSLog(@"并行隊(duì)列同步end");
}
//并行隊(duì)列異步
- (void)concurrentQueueAsyncMethod{
dispatch_queue_t queue = dispatch_queue_create("concurrentQueueAsyncMethod", DISPATCH_QUEUE_CONCURRENT);
for (int i = 0; i < 6; i++) {
dispatch_async(queue, ^{
NSLog(@"Current Thread=%@---->%d-----",[NSThread currentThread],i);
});
}
NSLog(@"并行隊(duì)列異步end");
}
并發(fā) 隊(duì)列同步執(zhí)行結(jié)果:
2016-11-03 17:49:33.850 ThreadDemo[27176:5290096] Current Thread=<NSThread: 0x60000007bf00>{number = 1, name = main}---->0-----
2016-11-03 17:49:33.851 ThreadDemo[27176:5290096] Current Thread=<NSThread: 0x60000007bf00>{number = 1, name = main}---->1-----
2016-11-03 17:49:33.851 ThreadDemo[27176:5290096] Current Thread=<NSThread: 0x60000007bf00>{number = 1, name = main}---->2-----
2016-11-03 17:49:33.851 ThreadDemo[27176:5290096] Current Thread=<NSThread: 0x60000007bf00>{number = 1, name = main}---->3-----
2016-11-03 17:49:33.851 ThreadDemo[27176:5290096] Current Thread=<NSThread: 0x60000007bf00>{number = 1, name = main}---->4-----
2016-11-03 17:49:33.851 ThreadDemo[27176:5290096] Current Thread=<NSThread: 0x60000007bf00>{number = 1, name = main}---->5-----
2016-11-03 17:49:33.851 ThreadDemo[27176:5290096] 并行隊(duì)列同步end
并發(fā)隊(duì)列 異步執(zhí)行結(jié)果:
2016-11-03 18:33:32.794 ThreadDemo[27283:5311953] 并行隊(duì)列異步end
2016-11-03 18:33:32.794 ThreadDemo[27283:5312009] Current Thread=<NSThread: 0x60800026b8c0>{number = 3, name = (null)}---->0-----
2016-11-03 18:33:32.794 ThreadDemo[27283:5312006] Current Thread=<NSThread: 0x600000269180>{number = 4, name = (null)}---->1-----
2016-11-03 18:33:32.794 ThreadDemo[27283:5312003] Current Thread=<NSThread: 0x600000268f80>{number = 6, name = (null)}---->3-----
2016-11-03 18:33:32.794 ThreadDemo[27283:5312174] Current Thread=<NSThread: 0x60800026b740>{number = 8, name = (null)}---->5-----
2016-11-03 18:33:32.794 ThreadDemo[27283:5312004] Current Thread=<NSThread: 0x60800026b7c0>{number = 5, name = (null)}---->2-----
2016-11-03 18:33:32.794 ThreadDemo[27283:5312173] Current Thread=<NSThread: 0x60800026b800>{number = 7, name = (null)}---->4-----
小結(jié):
- 并發(fā)隊(duì)列同步執(zhí)行和串行隊(duì)列同步執(zhí)行一樣,都不會(huì)開辟新線程号杠,block任務(wù)之間是同步執(zhí)行的蚪腋!
- 并發(fā)隊(duì)列異步執(zhí)行結(jié)果中看到開辟了多個(gè)線程,并且執(zhí)行順序也不是順序執(zhí)行姨蟋。因?yàn)?strong>異步開多線程的代名詞屉凯,并發(fā)是開多條線程的代名詞
- 有多個(gè)線程,操作進(jìn)來之后它會(huì)將這些隊(duì)列安排在可用的處理器上眼溶,同時(shí)保證先進(jìn)來的任務(wù)優(yōu)先處理悠砚。
- 以先進(jìn)先出的方式,并發(fā)調(diào)度隊(duì)列中的任務(wù)執(zhí)行
- 如果當(dāng)前調(diào)度的任務(wù)是同步執(zhí)行的堂飞,會(huì)等待任務(wù)執(zhí)行完成后灌旧,再調(diào)度后續(xù)的任務(wù)
- 如果當(dāng)前調(diào)度的任務(wù)是異步執(zhí)行的绑咱,同時(shí)底層線程池有可用的線程資源,會(huì)再新的線程調(diào)度后續(xù)任務(wù)的執(zhí)行
3. 全局隊(duì)列(Global Dispatch Queue)
全局隊(duì)列基本知識(shí)
-
dispatch_get_global_queue
函數(shù)來獲取 -
全局隊(duì)列是所有應(yīng)用程序都能夠使用的并發(fā)隊(duì)列(Concurrent Dispatch Queue)枢泰,沒必要通過
dispatch_queue_create
函數(shù)逐個(gè)生成并發(fā)隊(duì)列羡玛,只需要獲取Global Dispatch Queue即可 - 是系統(tǒng)為了方便程序員開發(fā)提供的,其工作表現(xiàn)與并發(fā)隊(duì)列一致宗苍、其工作表現(xiàn)與并發(fā)隊(duì)列一致稼稿、其工作表現(xiàn)與并發(fā)隊(duì)列一致
- Global Dispatch Queue有4個(gè)優(yōu)先級(jí),分別是高優(yōu)先級(jí)讳窟、默認(rèn)優(yōu)先級(jí)让歼、低優(yōu)先級(jí)、后臺(tái)優(yōu)先級(jí)丽啡!因?yàn)閄NU內(nèi)核用于Global Dispatch Queue的線程并不能保證實(shí)時(shí)性谋右,因此執(zhí)行優(yōu)先級(jí)知識(shí)大概的判斷和區(qū)分。
#define DISPATCH_QUEUE_PRIORITY_HIGH 2
#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0
#define DISPATCH_QUEUE_PRIORITY_LOW (-2)
#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN
全局隊(duì)列同步和異步執(zhí)行Demo
#pragma mark -全局隊(duì)列同步和全局隊(duì)列異步(工作表現(xiàn)與并發(fā)隊(duì)列一致)
//全局隊(duì)列同步
- (void)globalSyncMethod{
//獲取全局隊(duì)列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//執(zhí)行任務(wù)
for (int i = 0; i < 10; ++i) {
dispatch_sync(queue, ^{
NSLog(@"global_queue_sync%@---->%d----",[NSThread currentThread],i);
});
}
NSLog(@"global_queue_sync_end");
}
//全局隊(duì)列異步
- (void)globalAsyncMethod{
//獲取全局隊(duì)列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//執(zhí)行任務(wù)
for (int i = 0; i < 10; ++i) {
dispatch_async(queue, ^{
NSLog(@"global_queue_async%@---->%d----",[NSThread currentThread],i);
});
}
NSLog(@"global_queue_async_end");
}
全局隊(duì)列 同步執(zhí)行結(jié)果:
2016-11-03 19:06:02.650 ThreadDemo[27347:5324064] global_queue_sync<NSThread: 0x600000072200>{number = 1, name = main}---->0----
2016-11-03 19:06:02.651 ThreadDemo[27347:5324064] global_queue_sync<NSThread: 0x600000072200>{number = 1, name = main}---->1----
2016-11-03 19:06:02.651 ThreadDemo[27347:5324064] global_queue_sync<NSThread: 0x600000072200>{number = 1, name = main}---->2----
2016-11-03 19:06:02.651 ThreadDemo[27347:5324064] global_queue_sync<NSThread: 0x600000072200>{number = 1, name = main}---->3----
2016-11-03 19:06:02.651 ThreadDemo[27347:5324064] global_queue_sync<NSThread: 0x600000072200>{number = 1, name = main}---->4----
2016-11-03 19:06:02.651 ThreadDemo[27347:5324064] global_queue_sync<NSThread: 0x600000072200>{number = 1, name = main}---->5----
2016-11-03 19:06:02.652 ThreadDemo[27347:5324064] global_queue_sync<NSThread: 0x600000072200>{number = 1, name = main}---->6----
2016-11-03 19:06:02.652 ThreadDemo[27347:5324064] global_queue_sync<NSThread: 0x600000072200>{number = 1, name = main}---->7----
2016-11-03 19:06:02.652 ThreadDemo[27347:5324064] global_queue_sync<NSThread: 0x600000072200>{number = 1, name = main}---->8----
2016-11-03 19:06:02.652 ThreadDemo[27347:5324064] global_queue_sync<NSThread: 0x600000072200>{number = 1, name = main}---->9----
2016-11-03 19:06:02.652 ThreadDemo[27347:5324064] global_queue_sync_end
全局隊(duì)列 異步執(zhí)行結(jié)果:
2016-11-03 19:12:00.242 ThreadDemo[27430:5333537] global_queue_async_end
2016-11-03 19:12:00.242 ThreadDemo[27430:5334057] global_queue_async<NSThread: 0x608000266100>{number = 5, name = (null)}---->0----
2016-11-03 19:12:00.242 ThreadDemo[27430:5334053] global_queue_async<NSThread: 0x600000263c80>{number = 6, name = (null)}---->1----
2016-11-03 19:12:00.242 ThreadDemo[27430:5334056] global_queue_async<NSThread: 0x600000263cc0>{number = 7, name = (null)}---->2----
2016-11-03 19:12:00.242 ThreadDemo[27430:5334063] global_queue_async<NSThread: 0x608000268500>{number = 8, name = (null)}---->3----
2016-11-03 19:12:00.242 ThreadDemo[27430:5334064] global_queue_async<NSThread: 0x600000263b80>{number = 9, name = (null)}---->4----
2016-11-03 19:12:00.243 ThreadDemo[27430:5334057] global_queue_async<NSThread: 0x608000266100>{number = 5, name = (null)}---->5----
2016-11-03 19:12:00.243 ThreadDemo[27430:5334053] global_queue_async<NSThread: 0x600000263c80>{number = 6, name = (null)}---->7----
2016-11-03 19:12:00.243 ThreadDemo[27430:5334065] global_queue_async<NSThread: 0x600000073600>{number = 10, name = (null)}---->6----
2016-11-03 19:12:00.243 ThreadDemo[27430:5334056] global_queue_async<NSThread: 0x600000263cc0>{number = 7, name = (null)}---->8----
2016-11-03 19:12:00.243 ThreadDemo[27430:5334066] global_queue_async<NSThread: 0x608000267d40>{number = 11, name = (null)}---->9----
4. 主隊(duì)列(Main Dispatch Queue)
主隊(duì)列基本知識(shí)
-
dispatch_get_main_queue()
函數(shù)來獲取 - 專門用來在主線程上調(diào)度任務(wù)的隊(duì)列
- 不會(huì)開啟線程
- 以先進(jìn)先出的方式补箍,在主線程空閑時(shí)才會(huì)調(diào)度隊(duì)列中的任務(wù)在主線程執(zhí)行
- 如果當(dāng)前主線程正在有任務(wù)執(zhí)行改执,那么無論主隊(duì)列中當(dāng)前被添加了什么任務(wù),都不會(huì)被調(diào)度
主隊(duì)列同步和異步執(zhí)行Demo
#pragma mark -主隊(duì)列同步和主隊(duì)列異步
//主隊(duì)列同步
- (void)mainSyncMethod{
//獲取主隊(duì)列
dispatch_queue_t queue = dispatch_get_main_queue();
//執(zhí)行任務(wù)
for (int i = 0; i < 10; ++i) {
dispatch_sync(queue, ^{
NSLog(@"main_queue_sync%@---->%d----",[NSThread currentThread],i);
});
}
NSLog(@"main_queue_sync_end");
}
//主隊(duì)列異步
- (void)mainAsyncMethod{
//獲取主隊(duì)列
dispatch_queue_t queue = dispatch_get_main_queue();
//執(zhí)行任務(wù)
for (int i = 0; i < 10; ++i) {
dispatch_async(queue, ^{
NSLog(@"main_queue_async%@---->%d----",[NSThread currentThread],i);
});
}
NSLog(@"main_queue_async_end");
}
主隊(duì)列 同步執(zhí)行結(jié)果:
主線程和主隊(duì)列相互等待造成死鎖坑雅,程序會(huì)直接卡死辈挂!
原因:源代碼在Main Dispatch Queue 即主隊(duì)列中執(zhí)行指定的block任務(wù),并等待其結(jié)束裹粤。而其實(shí)在主線程中正在執(zhí)行這些源代碼终蒂,所以無法執(zhí)行追加到Main Dispatch Queue 的block任務(wù)。
下面例子也一樣:
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_async(queue, ^{
dispatch_sync(queue, ^{
NSLog(@"main_queue_sync%@----",[NSThread currentThread]);
});
});
主隊(duì)列 異步執(zhí)行結(jié)果:
2016-11-03 19:45:38.154 ThreadDemo[27501:5349956] main_queue_async_end
2016-11-03 19:45:38.155 ThreadDemo[27501:5349956] main_queue_async<NSThread: 0x608000070880>{number = 1, name = main}---->0----
2016-11-03 19:45:38.155 ThreadDemo[27501:5349956] main_queue_async<NSThread: 0x608000070880>{number = 1, name = main}---->1----
2016-11-03 19:45:38.155 ThreadDemo[27501:5349956] main_queue_async<NSThread: 0x608000070880>{number = 1, name = main}---->2----
2016-11-03 19:45:38.155 ThreadDemo[27501:5349956] main_queue_async<NSThread: 0x608000070880>{number = 1, name = main}---->3----
2016-11-03 19:45:38.155 ThreadDemo[27501:5349956] main_queue_async<NSThread: 0x608000070880>{number = 1, name = main}---->4----
2016-11-03 19:45:38.156 ThreadDemo[27501:5349956] main_queue_async<NSThread: 0x608000070880>{number = 1, name = main}---->5----
2016-11-03 19:45:38.156 ThreadDemo[27501:5349956] main_queue_async<NSThread: 0x608000070880>{number = 1, name = main}---->6----
2016-11-03 19:45:38.156 ThreadDemo[27501:5349956] main_queue_async<NSThread: 0x608000070880>{number = 1, name = main}---->7----
2016-11-03 19:45:38.156 ThreadDemo[27501:5349956] main_queue_async<NSThread: 0x608000070880>{number = 1, name = main}---->8----
2016-11-03 19:45:38.156 ThreadDemo[27501:5349956] main_queue_async<NSThread: 0x608000070880>{number = 1, name = main}---->9----
5.延遲執(zhí)行(dispatch_after)
- 在GCD中我們使用dispatch_after()函數(shù)來延遲執(zhí)行隊(duì)列中的任務(wù), dispatch_after()是異步執(zhí)行隊(duì)列中的任務(wù)的遥诉,也就是說使用dispatch_after()來執(zhí)行隊(duì)列中的任務(wù)不會(huì)阻塞當(dāng)前任務(wù)拇泣。等到延遲時(shí)間到了以后就會(huì)開辟一個(gè)新的線程然后執(zhí)行隊(duì)列中的任務(wù)。
-
dispatch_after(dispatch_time_t when,dispatch_queue_t queue,dispatch_block_t block);
來創(chuàng)建 - 經(jīng)過我的猜測測試(看不到源碼)矮锈,你們也思考一下這個(gè)延遲函數(shù)的實(shí)現(xiàn)過程霉翔。底層實(shí)現(xiàn)應(yīng)該是dispath_async函數(shù)追加block到Main Dispatch Queue等相應(yīng)隊(duì)列,偽代碼如下(以Main Dispatch Queue為例):
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
delay(2){
dispatch_async(queue, ^{
dispatch_async(dispatch_get_main_queue(), ^{
add task to mainQueue
});
});
}
延遲執(zhí)行(dispatch_after)Demo
#pragma mark - 延遲執(zhí)行
- (void)GCDAfterRunMethod{
// 循環(huán)5次
for (int i =0; i < 10000; i++ ) {
NSLog(@"let's go %d",i);
// 設(shè)置2秒后執(zhí)行block
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC));
dispatch_after(time, dispatch_get_main_queue(), ^{
NSLog(@"This is my %d number!%@",i,[NSThread currentThread]);
});
}
//等價(jià)于下面實(shí)現(xiàn)
// dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
// for (int i = 0; i < 10000; i++) { // NSLog(@"let's go %d",i);
// dispatch_async(queue, ^{
// dispatch_async(dispatch_get_main_queue(), ^{ // NSLog(@"This is my %d number!%@",i,[NSThread currentThread]);
// });
// });
// }
}
注意:
dispatch_after(dispatch_time_t when,dispatch_queue_t queue,dispatch_block_t block);
- 第二個(gè)參數(shù):指定要追加處理的Dispatch Queue
- 第三個(gè)參數(shù):指定要執(zhí)行處理的Block
- 第一個(gè)參數(shù):指定時(shí)間用的
dispatch_time_t
類型的值苞笨,該值是使用dispatch_time
函數(shù)或者dispatch_walltime
函數(shù)生成
1.dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC));
里面有兩個(gè)參數(shù):
參數(shù)1獲取指定的時(shí)間開始债朵,通常為DISPATCH_TIME_NOW,定義:
#define DISPATCH_TIME_NOW (0ull)//現(xiàn)在
#define DISPATCH_TIME_FOREVER (~0ull)//永遠(yuǎn)猫缭,意味著你用它你的任務(wù)永遠(yuǎn)不會(huì)執(zhí)行了葱弟!
參數(shù)2是從參數(shù)1延遲指定的時(shí)間來執(zhí)行任務(wù),也是一個(gè)時(shí)間
#define NSEC_PER_SEC 1000000000ull
#define NSEC_PER_MSEC 1000000ull
#define USEC_PER_SEC 1000000ull
#define NSEC_PER_USEC 1000ull
ull是C語言的數(shù)值字面量猜丹,是顯示表明類型是使用的字符串(表示“unsigned long long”)
NSEC_PER_SEC 是秒的單位數(shù)量級(jí) 等價(jià)于1億納秒
上面代碼中提到的(int64_t)(2 * NSEC_PER_SEC))就是2秒了
2.使用dispatch_walltime
函數(shù)生成dispatch_time_t
,用于計(jì)算絕對(duì)時(shí)間芝加,例如在dispatch_after函數(shù)中指定2016年11月3日21時(shí)45分1秒這一絕對(duì)時(shí)間,可粗略的鬧鐘功能來使用。也就是到指定時(shí)間就會(huì)執(zhí)行任務(wù)
//由NSDate類對(duì)象獲取dispatch_time_t傳遞給dispatch_after函數(shù)使用
dispatch_time_t getDispatchTimeByDate(NSDate *date){
NSTimeInterval interval;
double second,subSecond;
struct timespec time;
dispatch_time_t milestone;
interval = [date timeIntervalSince1970];
subSecond = modf(interval, &second);
time.tv_sec = second;
time.tv_nsec = subSecond * NSEC_PER_SEC;
milestone = dispatch_walltime(&time, 0);
return milestone;
}
6. 更改優(yōu)先級(jí)(dispatch_set_target_queue)
dispatch_queue_create
函數(shù)生成的Dispatch Queue不管是 串行隊(duì)列(Serial Dispatch Queue) 還是 并發(fā)隊(duì)列(Concurrent Dispatch Queue) 藏杖,都是用與 默認(rèn)優(yōu)先級(jí)全局隊(duì)列(Global Dispatch Queue)相同執(zhí)行優(yōu)先級(jí)的線程将塑。而全局隊(duì)列工作方式與并發(fā)隊(duì)列工作方式完全一致!-
dispatch_set_target_queue(dispatch_object_t object,dispatch_queue_t _Nullable queue);
函數(shù)來更改隊(duì)列優(yōu)先級(jí)- 第一個(gè)參數(shù):指定要變更優(yōu)先級(jí)的隊(duì)列(要更改隊(duì)列)
- 第二個(gè)參數(shù):指定第一個(gè)參數(shù)(隊(duì)列)要和我們預(yù)期隊(duì)列執(zhí)行相同優(yōu)先級(jí)的隊(duì)列(目標(biāo)隊(duì)列)
1. dispatch_set_target_queue第一個(gè)Demo:
- (void)GCDSetTargetQueueMethod{
dispatch_queue_t targetQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
dispatch_queue_t queue1 = dispatch_queue_create("queue1", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t queue2 = dispatch_queue_create("queue2", DISPATCH_QUEUE_CONCURRENT);
//更改優(yōu)先級(jí)
dispatch_set_target_queue(queue1, targetQueue);
for (int i = 0; i < 6; i++) {
dispatch_async(queue1, ^{
NSLog(@"queue1-currentThread = %@-->%d",[NSThread currentThread],i);
});
}
for (int i = 0; i < 6; i++) {
dispatch_async(queue2, ^{
NSLog(@"queue2-----currentThread = %@----->%d",[NSThread currentThread],i);
});
}
}
打印結(jié)果:
2016-11-04 11:14:57.034 ThreadDemo[28477:5530919] queue2-----currentThread = <NSThread: 0x60000007e0c0>{number = 11, name = (null)}----->1
2016-11-04 11:14:57.034 ThreadDemo[28477:5530920] queue2-----currentThread = <NSThread: 0x60000007a140>{number = 12, name = (null)}----->2
2016-11-04 11:14:57.034 ThreadDemo[28477:5530918] queue2-----currentThread = <NSThread: 0x60000007a100>{number = 10, name = (null)}----->0
2016-11-04 11:14:57.034 ThreadDemo[28477:5530919] queue2-----currentThread = <NSThread: 0x60000007e0c0>{number = 11, name = (null)}----->3
2016-11-04 11:14:57.034 ThreadDemo[28477:5530912] queue1-currentThread = <NSThread: 0x60000007ec00>{number = 9, name = (null)}-->0
2016-11-04 11:14:57.034 ThreadDemo[28477:5530920] queue2-----currentThread = <NSThread: 0x60000007a140>{number = 12, name = (null)}----->5
2016-11-04 11:14:57.034 ThreadDemo[28477:5530921] queue2-----currentThread = <NSThread: 0x60000007c340>{number = 13, name = (null)}----->4
2016-11-04 11:14:57.035 ThreadDemo[28477:5530912] queue1-currentThread = <NSThread: 0x60000007ec00>{number = 9, name = (null)}-->1
2016-11-04 11:14:57.036 ThreadDemo[28477:5530912] queue1-currentThread = <NSThread: 0x60000007ec00>{number = 9, name = (null)}-->2
2016-11-04 11:14:57.036 ThreadDemo[28477:5530912] queue1-currentThread = <NSThread: 0x60000007ec00>{number = 9, name = (null)}-->3
2016-11-04 11:14:57.036 ThreadDemo[28477:5530912] queue1-currentThread = <NSThread: 0x60000007ec00>{number = 9, name = (null)}-->4
2016-11-04 11:14:57.037 ThreadDemo[28477:5530912] queue1-currentThread = <NSThread: 0x60000007ec00>{number = 9, name = (null)}-->5
打印解釋:
- queue1和queue2設(shè)置的目標(biāo)隊(duì)列是全局隊(duì)列(并發(fā)),也就是允許要更改的隊(duì)列可以開辟多條線程(可以超過一條)
- 代碼中queue1變更和低優(yōu)先級(jí)的全局隊(duì)列一樣優(yōu)先級(jí)的串行隊(duì)列蝌麸,queue2是dispatch_queue_create創(chuàng)建和默認(rèn)優(yōu)先級(jí)的全局隊(duì)列一樣優(yōu)先級(jí)的并發(fā)隊(duì)列点寥。
- queue1和queue2都是異步執(zhí)行,都會(huì)開辟線程来吩,queue2是并發(fā)隊(duì)列所以打印中看到有多個(gè)線程敢辩,并且任務(wù)之間也不是順序執(zhí)行。queue1是串行隊(duì)列弟疆,所以只會(huì)開辟一個(gè)線程戚长,任務(wù)會(huì)順序執(zhí)行。
- queue2隊(duì)列的優(yōu)先級(jí)比queue1隊(duì)列的優(yōu)先級(jí)要高怠苔,從打印中可以看到queue2的確比queue1任務(wù)要普遍先執(zhí)行同廉。為什么要說普遍呢,因?yàn)閺慕Y(jié)果上看到queue1有一個(gè)任務(wù)是在queue2里任務(wù)沒有執(zhí)行完畢也執(zhí)行了柑司,為什么會(huì)出現(xiàn)這個(gè)問題呢迫肖??
在上面全局隊(duì)列中說到了優(yōu)先級(jí)的事情
因?yàn)閄NU內(nèi)核用于Global Dispatch Queue的線程并不能保證實(shí)時(shí)性攒驰,因此執(zhí)行優(yōu)先級(jí)知識(shí)大概的判斷和區(qū)分蟆湖,
所有我們不能完全依賴這個(gè)優(yōu)先級(jí)來做隊(duì)列的順序事情,否則會(huì)出現(xiàn)問題讼育!切記
2. dispatch_set_target_queue第一個(gè)Demo:
-
dispatch_set_target_queue除了能用來設(shè)置隊(duì)列的優(yōu)先級(jí)之外帐姻,還能夠創(chuàng)建隊(duì)列的執(zhí)行層次
,當(dāng)我們想讓不同隊(duì)列中的任務(wù)同步的執(zhí)行時(shí)奶段,我們可以創(chuàng)建一個(gè)串行隊(duì)列,然后將這些隊(duì)列的target指向新創(chuàng)建的隊(duì)列即可剥纷,比如:
- (void)GCDSetTargetQueueMethod{
dispatch_queue_t targetQueue = dispatch_queue_create("targetQueue", DISPATCH_QUEUE_SERIAL);//目標(biāo)隊(duì)列
dispatch_queue_t queue1 = dispatch_queue_create("queue1", DISPATCH_QUEUE_SERIAL);//串行隊(duì)列
dispatch_queue_t queue2 = dispatch_queue_create("queue2", DISPATCH_QUEUE_CONCURRENT);//并發(fā)隊(duì)列
//設(shè)置參考
dispatch_set_target_queue(queue1, targetQueue);
dispatch_set_target_queue(queue2, targetQueue);
for (int i = 0; i < 6; i++) {
dispatch_async(queue1, ^{
NSLog(@"queue1-currentThread = %@-->%d",[NSThread currentThread],i);
});
}
for (int i = 0; i < 6; i++) {
dispatch_async(queue2, ^{
NSLog(@"queue2-currentThread = %@-->%d",[NSThread currentThread],i);
});
}
}
打印結(jié)果:
2016-11-04 11:34:34.722 ThreadDemo[28551:5540844] queue1-currentThread = <NSThread: 0x60000007b640>{number = 3, name = (null)}-->0
2016-11-04 11:34:34.723 ThreadDemo[28551:5540844] queue1-currentThread = <NSThread: 0x60000007b640>{number = 3, name = (null)}-->1
2016-11-04 11:34:34.723 ThreadDemo[28551:5540844] queue1-currentThread = <NSThread: 0x60000007b640>{number = 3, name = (null)}-->2
2016-11-04 11:34:34.723 ThreadDemo[28551:5540844] queue1-currentThread = <NSThread: 0x60000007b640>{number = 3, name = (null)}-->3
2016-11-04 11:34:34.723 ThreadDemo[28551:5540844] queue1-currentThread = <NSThread: 0x60000007b640>{number = 3, name = (null)}-->4
2016-11-04 11:34:34.723 ThreadDemo[28551:5540844] queue1-currentThread = <NSThread: 0x60000007b640>{number = 3, name = (null)}-->5
2016-11-04 11:34:34.724 ThreadDemo[28551:5540844] queue2-currentThread = <NSThread: 0x60000007b640>{number = 3, name = (null)}-->0
2016-11-04 11:34:34.724 ThreadDemo[28551:5540844] queue2-currentThread = <NSThread: 0x60000007b640>{number = 3, name = (null)}-->1
2016-11-04 11:34:34.724 ThreadDemo[28551:5540844] queue2-currentThread = <NSThread: 0x60000007b640>{number = 3, name = (null)}-->2
2016-11-04 11:34:34.724 ThreadDemo[28551:5540844] queue2-currentThread = <NSThread: 0x60000007b640>{number = 3, name = (null)}-->3
2016-11-04 11:34:34.724 ThreadDemo[28551:5540844] queue2-currentThread = <NSThread: 0x60000007b640>{number = 3, name = (null)}-->4
2016-11-04 11:34:34.725 ThreadDemo[28551:5540844] queue2-currentThread = <NSThread: 0x60000007b640>{number = 3, name = (null)}-->5
打印解釋:
- queue1和queue2設(shè)置的目標(biāo)隊(duì)列是串行隊(duì)列,也就是允許要更改的隊(duì)列可以開辟一條線程痹籍。
- queue1和queue2優(yōu)先級(jí)一樣,他兩執(zhí)行順序相當(dāng)于一個(gè)串行隊(duì)列異步執(zhí)行晦鞋!
- queue1和queue2隊(duì)列以targetQueue隊(duì)列為參照對(duì)象蹲缠,那么queue1和queue2中的任務(wù)將按照targetQueue的隊(duì)列處理。
- 適用場景:一般都是把一個(gè)任務(wù)放到一個(gè)串行的queue中悠垛,如果這個(gè)任務(wù)被拆分了线定,被放置到多個(gè)串行的queue中,但實(shí)際還是需要這個(gè)任務(wù)同步執(zhí)行确买,那么就會(huì)有問題斤讥,因?yàn)槎鄠€(gè)串行queue之間是并行的。這時(shí)候dispatch_set_target_queue將起到作用湾趾。
** dispatch_set_target_queue小結(jié):**
- dispatch_set_target_queue可以更改Dispatch Queue優(yōu)先級(jí)芭商。
- dispatch_set_target_queue可以更改隊(duì)列的執(zhí)行層次派草,隊(duì)列里的任務(wù)將會(huì)按照目標(biāo)隊(duì)列(target Queue)的隊(duì)列來處理
7. 任務(wù)組Dispatch Group
- GCD的任務(wù)組在開發(fā)中是經(jīng)常被使用到,
當(dāng)你一組任務(wù)結(jié)束后再執(zhí)行一些操作時(shí)铛楣,使用任務(wù)組在合適不過了
近迁。dispatch_group的職責(zé)就是當(dāng)隊(duì)列中的所有任務(wù)都執(zhí)行完畢后在去做一些操作,也就是說在任務(wù)組中執(zhí)行的隊(duì)列簸州,當(dāng)隊(duì)列中的所有任務(wù)都執(zhí)行完畢后就會(huì)發(fā)出一個(gè)通知來告訴用戶任務(wù)組中所執(zhí)行的隊(duì)列中的任務(wù)執(zhí)行完畢了鉴竭。關(guān)于將隊(duì)列放到任務(wù)組中執(zhí)行有兩種方式,一種是使用dispatch_group_async()
函數(shù)岸浑,將隊(duì)列與任務(wù)組進(jìn)行關(guān)聯(lián)并自動(dòng)執(zhí)行隊(duì)列中的任務(wù)搏存。另一種方式是手動(dòng)的將隊(duì)列與組進(jìn)行關(guān)聯(lián)然后使用異步將隊(duì)列進(jìn)行執(zhí)行,也就是dispatch_group_enter()
與dispatch_group_leave()
方法的使用助琐。下方就給出詳細(xì)的介紹祭埂。
1.隊(duì)列與組自動(dòng)關(guān)聯(lián)并執(zhí)行
- 首先我們來介紹
dispatch_group_async()
函數(shù)的使用方式,該函數(shù)會(huì)將隊(duì)列與相應(yīng)的任務(wù)組進(jìn)行關(guān)聯(lián)兵钮,并且自動(dòng)執(zhí)行蛆橡。當(dāng)與任務(wù)組關(guān)聯(lián)的隊(duì)列中的任務(wù)都執(zhí)行完畢后,會(huì)通過dispatch_group_notify()
函數(shù)發(fā)出通知告訴用戶任務(wù)組中的所有任務(wù)都執(zhí)行完畢了掘譬。使用通知的方式是不會(huì)阻塞當(dāng)前線程的
泰演,如果你使用dispatch_group_wait()函數(shù),那么就會(huì)阻塞當(dāng)前線程葱轩,直到任務(wù)組中的所有任務(wù)都執(zhí)行完畢睦焕。
//自動(dòng)執(zhí)行任務(wù)組
- (void)GCDAutoDispatchGroupMethod{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();
for (int i = 0; i < 6; i++) {
dispatch_group_async(group, queue, ^{
NSLog(@"current Thread = %@----->%d",[NSThread currentThread],i);
});
}
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"current Thread = %@----->這是最后執(zhí)行",[NSThread currentThread]);
});
}
打印結(jié)果:
2016-11-04 15:11:34.010 ThreadDemo[29225:5641180] current Thread = <NSThread: 0x600000468200>{number = 5, name = (null)}----->2
2016-11-04 15:11:34.010 ThreadDemo[29225:5641193] current Thread = <NSThread: 0x60800007f900>{number = 3, name = (null)}----->0
2016-11-04 15:11:34.011 ThreadDemo[29225:5641438] current Thread = <NSThread: 0x608000467980>{number = 8, name = (null)}----->5
2016-11-04 15:11:34.010 ThreadDemo[29225:5641178] current Thread = <NSThread: 0x608000467640>{number = 6, name = (null)}----->3
2016-11-04 15:11:34.010 ThreadDemo[29225:5641177] current Thread = <NSThread: 0x6080004675c0>{number = 4, name = (null)}----->1
2016-11-04 15:11:34.010 ThreadDemo[29225:5641437] current Thread = <NSThread: 0x600000467f40>{number = 7, name = (null)}----->4
2016-11-04 15:11:34.011 ThreadDemo[29225:5641137] current Thread = <NSThread: 0x60800007e200>{number = 1, name = main}----->這是最后執(zhí)行
上面的函數(shù)就是使用
dispatch_group_async()
函數(shù)將隊(duì)列與任務(wù)組進(jìn)行關(guān)聯(lián)并執(zhí)行。首先我們創(chuàng)建了一個(gè)全局隊(duì)列(并發(fā))靴拱,然后又創(chuàng)建了一個(gè)類型為dispatch_group_t
的任務(wù)組group垃喊。使用dispatch_group_async()
函數(shù)將兩者進(jìn)行關(guān)聯(lián)并執(zhí)行。使用dispatch_group_notify()
函數(shù)進(jìn)行監(jiān)聽group中隊(duì)列的執(zhí)行結(jié)果袜炕,如果執(zhí)行完畢后本谜,我們就在主線程中對(duì)結(jié)果進(jìn)行處理。dispatch_group_notify()
函數(shù)有兩個(gè)參數(shù)一個(gè)是發(fā)送通知的group偎窘,另一個(gè)是處理返回結(jié)果的隊(duì)列乌助。dispatch_group_async(dispatch_group_t group,dispatch_queue_t queue,dispatch_block_t block);
函數(shù)與dispatch_async
函數(shù)相同,都追加block到指定的Dispatch Queue中陌知,與dispatch_async不同的是指定生成的Dispatch Group為第一個(gè)參數(shù)他托。指定的block屬于指定的Dispatch Group,不是Dispatch Queue仆葡,切記赏参!
無論向什么樣的Dispatch Queue中追加處理,使用Dispatch Group都可監(jiān)視這些處理執(zhí)行的結(jié)束。一旦檢測到所有處理執(zhí)行結(jié)束登刺,就可將結(jié)束的處理追加到Dispatch Queue中籽腕。這就是使用Dispatch Group的原因。
在追加到Dispatch Group中的處理全部執(zhí)行結(jié)束時(shí)纸俭,代碼中使用的
dispatch_group_notify
函數(shù)會(huì)將執(zhí)行的Block追加到Dispatch Queue中皇耗,將第一個(gè)參數(shù)指定為要監(jiān)視的Dispatch Group。在追加到該Dispatch Group的全部處理執(zhí)行結(jié)束時(shí)揍很,將第三個(gè)參數(shù)的Block追加到第二個(gè)參數(shù)的Dispatch Queue中郎楼。在dispatch_group_notify函數(shù)中不管指定什么樣的Dispatch Queue,屬于Dispatch Group的全部處理在追加指定的Block時(shí)都已執(zhí)行結(jié)束窒悔。另外呜袁,在Dispatch Group中也可以使用
dispatch_group_wait
函數(shù)僅等待全部處理執(zhí)行結(jié)束。
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{NSLog(@"blk0");});
dispatch_group_async(group, queue, ^{NSLog(@"blk1");});
dispatch_group_async(group, queue, ^{NSLog(@"blk2");});
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
-
dispatch_group_wait
函數(shù)的第二個(gè)參數(shù)指定為等待時(shí)間(超時(shí))简珠。它屬于dispatch_time_t類型的值阶界。代碼中使用的DISPATCH_TIME_FOREVER
,意味著永久等待聋庵。只要屬于Dispatch Group的操作尚未執(zhí)行結(jié)束膘融,就會(huì)一直等待,中途不能取消祭玉。指定等待時(shí)間為1微秒時(shí)氧映,應(yīng)做如下處理:
//等待group處理結(jié)束
// dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1*USEC_PER_SEC));//1微秒
long result = dispatch_group_wait(group, time);
if (result == 0) {
//屬于Dispatch Group 的block任務(wù)全部處理結(jié)束
NSLog(@"Dispatch Group全部處理完畢");
}else{
//屬于Dispatch Group 的block任務(wù)還在處理中
NSLog(@"Dispatch Group正在處理");
}
如果dispatch_group_wait函數(shù)的返回值不為0,就意味著雖然經(jīng)過了指定的時(shí)間脱货,但屬于Dispatch Group的某一個(gè)處理還在執(zhí)行中岛都。如果返回值為0,那么全部處理執(zhí)行結(jié)束振峻。當(dāng)?shù)却龝r(shí)間為DISPATCH_TIME_FOREVER臼疫,由dispatch_group_wait函數(shù)返回時(shí),屬于Dispatch Group的處理必定全部執(zhí)行結(jié)束扣孟,因此返回值恒為0多矮。
這里的“等待”是什么意思?
這意味著一旦調(diào)用dispatch_group_wait函數(shù)哈打,該函數(shù)就處于調(diào)用的狀態(tài)而不返回。即執(zhí)行dispatch_group_wait函數(shù)的現(xiàn)在的線程(當(dāng)前線程)停止讯壶。在經(jīng)過dispatch_group_wait函數(shù)中指定的時(shí)間或?qū)儆谥付―ispatch Group的處理全部執(zhí)行結(jié)束之前料仗,執(zhí)行該函數(shù)的線程停止,屬于阻塞狀態(tài)伏蚊。
指定
DISPACH_TIME_NOW
立轧,則不用任何等待即可判定屬于Dispatch Group的處理是否執(zhí)行結(jié)束。
long result = diaptach_group_wait(group, DISPACH_TIME_NOW);
- 在主線程的RunLoop的每次循環(huán)中,可檢查執(zhí)行是否結(jié)束氛改,從而不消耗多余的等待時(shí)間帐萎,雖然這樣有額可以,但一般在這種情況下胜卤,還是推薦用
dispatch_group_notify
函數(shù)追加結(jié)束處理到Main Dispatch Queue中疆导。這是因?yàn)?code>dispatch_group_notify函數(shù)可以簡化代碼。并且如果你用了diaptach_group_wait
等待時(shí)間過長葛躏,中間不能取消隊(duì)列任務(wù)這就很坑了澈段!
2. 隊(duì)列與組手動(dòng)關(guān)聯(lián)并執(zhí)行
- 接下來我們將手動(dòng)的管理任務(wù)組與隊(duì)列中的關(guān)系,也就是不使用
dispatch_group_async()
函數(shù)舰攒。我們使用dispatch_group_enter()
與dispatch_group_leave()
函數(shù)將隊(duì)列中的每次任務(wù)加入到到任務(wù)組中败富。首先我們使用dispatch_group_enter()
函數(shù)進(jìn)入到任務(wù)組中,然后異步執(zhí)行隊(duì)列中的任務(wù)摩窃,最后使用dispatch_group_leave()
函數(shù)離開任務(wù)組即可兽叮。下面的函數(shù)中我們使用了dispatch_group_wait()
函數(shù),該函數(shù)的職責(zé)就是阻塞當(dāng)前線程猾愿,來等待任務(wù)組中的任務(wù)執(zhí)行完畢鹦聪。該函數(shù)的第一個(gè)參數(shù)是所要等待的group,第二個(gè)參數(shù)是等待超時(shí)時(shí)間匪蟀,此處我們設(shè)置的是DISPATCH_TIME_FOREVER
椎麦,就說明等待任務(wù)組的執(zhí)行永不超時(shí),直到任務(wù)組中所有任務(wù)執(zhí)行完畢材彪。
//手動(dòng)執(zhí)行任務(wù)組
- (void)GCDManualDispatchGroupMethod{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();
for (int i = 0; i < 6; i++) {
dispatch_group_enter(group);//進(jìn)入隊(duì)列組
dispatch_async(queue, ^{
NSLog(@"current Thread = %@----->%d",[NSThread currentThread],i);
dispatch_group_leave(group);//離開隊(duì)列組
});
}
long result = dispatch_group_wait(group, DISPATCH_TIME_FOREVER);//阻塞當(dāng)前線程观挎,直到所有任務(wù)執(zhí)行完畢才會(huì)繼續(xù)往下執(zhí)行
if (result == 0) {
//屬于Dispatch Group 的block任務(wù)全部處理結(jié)束
NSLog(@"Dispatch Group全部處理完畢");
}else{
//屬于Dispatch Group 的block任務(wù)還在處理中
NSLog(@"Dispatch Group正在處理");
}
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"current Thread = %@----->這是最后執(zhí)行",[NSThread currentThread]);
});
}
打印結(jié)果:dispatch_group_wait()
函數(shù)下方的print()函數(shù)在所有任務(wù)執(zhí)行完畢之前是不會(huì)被調(diào)用的,因?yàn)?code>dispatch_group_wait()會(huì)將當(dāng)前線程進(jìn)行阻塞段化。當(dāng)然雖然是手動(dòng)的將隊(duì)列與任務(wù)組進(jìn)行關(guān)聯(lián)的嘁捷,感覺display_group_notify()
函數(shù)還是好用的。
2016-11-04 16:19:13.802 ThreadDemo[29402:5678525] current Thread = <NSThread: 0x600000271780>{number = 5, name = (null)}----->2
2016-11-04 16:19:13.802 ThreadDemo[29402:5678527] current Thread = <NSThread: 0x608000077300>{number = 3, name = (null)}----->0
2016-11-04 16:19:13.802 ThreadDemo[29402:5678524] current Thread = <NSThread: 0x60800007d840>{number = 4, name = (null)}----->1
2016-11-04 16:19:13.803 ThreadDemo[29402:5678760] current Thread = <NSThread: 0x600000271cc0>{number = 8, name = (null)}----->5
2016-11-04 16:19:13.802 ThreadDemo[29402:5678545] current Thread = <NSThread: 0x60800007d000>{number = 6, name = (null)}----->3
2016-11-04 16:19:13.802 ThreadDemo[29402:5678544] current Thread = <NSThread: 0x60800007d040>{number = 7, name = (null)}----->4
2016-11-04 16:19:13.803 ThreadDemo[29402:5678489] Dispatch Group全部處理完畢
2016-11-04 16:19:13.804 ThreadDemo[29402:5678489] current Thread = <NSThread: 0x600000069dc0>{number = 1, name = main}----->這是最后執(zhí)行
8. 柵欄任務(wù)Dispatch_barrier_async
-
barrier顧名思義柵欄显熏、障礙物的意思雄嚣!
在訪問數(shù)據(jù)庫或文件時(shí),使用Serial Dispatch Queue可避免數(shù)據(jù)競爭的問題喘蟆。寫入處理確實(shí)不可與其他的寫入處理以及包含讀取處理的其他某些處理并行執(zhí)行缓升。但是如果讀取處理只是與讀取處理并行執(zhí)行,那么多個(gè)并行執(zhí)行就不會(huì)發(fā)生問題蕴轨。
也就是說港谊,為了高效率地進(jìn)行訪問,讀取處理追加到Concurrent Dispatch Queue中橙弱,寫入出路在任何一個(gè)讀取處理沒有執(zhí)行的狀態(tài)下歧寺,追加到Serial Dispatch Queue中即可(在寫入處理結(jié)束之前燥狰,讀取處理不可執(zhí)行)。
雖然利用Dispatch Group和dispatch_set_target_queue函數(shù)也可實(shí)現(xiàn)斜筐,但代碼會(huì)很復(fù)雜龙致。有興趣的可以自己嘗試寫寫!
CD為我們提供了更為聰明的解決辦法——dispatch_barrier_async
函數(shù)顷链。該函數(shù)同dispatch_queue_create函數(shù)生成的Concurrent Dispatch Queue一起使用目代。
#pragma mark - Dispatch_barrier_async
- (void)GCDBarrierAsyncMethod{
dispatch_queue_t concurrentQueue = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
void(^blk1_reading)(void) = ^{
NSLog(@"blk1---reading");
};
void(^blk2_reading)(void) = ^{
NSLog(@"blk2---reading");
};
void(^blk3_reading)(void) = ^{
NSLog(@"blk3---reading");
};
void(^blk4_reading)(void) = ^{
NSLog(@"blk4---reading");
};
void(^blk_writing)(void) = ^{
NSLog(@"blk---writing");
};
dispatch_async(concurrentQueue, blk1_reading);
dispatch_async(concurrentQueue, blk2_reading);
//添加追加操作,,會(huì)等待b1和b2全部執(zhí)行結(jié)束,執(zhí)行完成追加操作b蕴潦,才會(huì)繼續(xù)并發(fā)執(zhí)行下面操作
dispatch_barrier_async(concurrentQueue, blk_writing);
dispatch_async(concurrentQueue, blk3_reading);
dispatch_async(concurrentQueue, blk4_reading);
}
打印結(jié)果:
2016-11-04 17:02:13.202 ThreadDemo[29492:5700974] blk2---reading
2016-11-04 17:02:13.202 ThreadDemo[29492:5700972] blk1---reading
2016-11-04 17:02:13.203 ThreadDemo[29492:5700972] blk---writing
2016-11-04 17:02:13.203 ThreadDemo[29492:5700972] blk3---reading
2016-11-04 17:02:13.203 ThreadDemo[29492:5700974] blk4---reading
- 使用
Concurrent Dispatch Queue
和dispatch_barrier_async
函數(shù)可實(shí)現(xiàn)高效率的數(shù)據(jù)庫訪問和文件訪問,dispatch_barrier_async
函數(shù)還是比較好理解的像啼。
9. 循環(huán)執(zhí)行dispatch_apply
- dispatch_apply()函數(shù)是用來循環(huán)來執(zhí)行隊(duì)列中的任務(wù)的,使用方式為:
dispatch_apply(循環(huán)次數(shù), 任務(wù)所在的隊(duì)列) { 要循環(huán)執(zhí)行的任務(wù) }
潭苞。使用該函數(shù)循環(huán)執(zhí)行并行隊(duì)列中的任務(wù)時(shí)忽冻,會(huì)開辟新的線程,不過有可能會(huì)在當(dāng)前線程中執(zhí)行一些任務(wù)此疹。而使用dispatch_apply()執(zhí)行串行隊(duì)列中的任務(wù)時(shí)僧诚,會(huì)在當(dāng)前線程中執(zhí)行。無論是使用并行隊(duì)列還是串行隊(duì)列蝗碎,dispatch_apply()都會(huì)阻塞當(dāng)前執(zhí)行函數(shù)線程湖笨。
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_apply(10, queue, ^(size_t index){
NSLog(@"%zu", index);
});
NSLog(@"done");
2016-11-04 17:24:25.819 ThreadDemo[29598:5715955] 2
2016-11-04 17:24:25.819 ThreadDemo[29598:5715904] 0
2016-11-04 17:24:25.819 ThreadDemo[29598:5716588] 1
2016-11-04 17:24:25.819 ThreadDemo[29598:5716640] 3
2016-11-04 17:24:25.820 ThreadDemo[29598:5715955] 4
2016-11-04 17:24:25.820 ThreadDemo[29598:5715904] 5
2016-11-04 17:24:25.820 ThreadDemo[29598:5716588] 6
2016-11-04 17:24:25.820 ThreadDemo[29598:5716640] 7
2016-11-04 17:24:25.820 ThreadDemo[29598:5715904] 9
2016-11-04 17:24:25.820 ThreadDemo[29598:5715955] 8
2016-11-04 17:24:25.820 ThreadDemo[29598:5715904] done
輸出結(jié)果中最后的done必定在最后的位置上,這是因?yàn)閐ispatch_apply函數(shù)會(huì)等待全部處理執(zhí)行結(jié)束蹦骑,也就是阻塞當(dāng)前執(zhí)行函數(shù)線程慈省。
另外,由于
dispatch_apply
函數(shù)也與dispatch_sync
函數(shù)相同眠菇,會(huì)等待處理執(zhí)行結(jié)束(阻塞)边败,因此推薦在dispatch_async
函數(shù)中非同步地執(zhí)行dispatch_apply
函數(shù)。
#pragma mark - Dispatch_apply
- (void)GCDDispatchApplyMethod{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
void(^blk1_reading)(void) = ^{
NSLog(@"blk1---reading");
};
void(^blk2_reading)(void) = ^{
NSLog(@"blk2---reading");
};
void(^blk3_reading)(void) = ^{
NSLog(@"blk3---reading");
};
void(^blk_writing)(void) = ^{
NSLog(@"blk---writing");
};
NSMutableArray *array = [NSMutableArray new];
[array addObject:blk1_reading];
[array addObject:blk2_reading];
[array addObject:blk3_reading];
[array addObject:blk_writing];
dispatch_async(queue, ^{
dispatch_apply(array.count, queue, ^(size_t index) {
void (^blk)(void) = [array objectAtIndex:index];
blk();
NSLog(@"%zu====%@",index,[array objectAtIndex:index]);
});
NSLog(@"全部執(zhí)行結(jié)束");
dispatch_async(dispatch_get_main_queue(), ^{
//在main Dispatch queue中執(zhí)行處理捎废,更新用戶界面等待
NSLog(@"done");
});
});
}
打印結(jié)果:
2016-11-04 17:36:02.258 ThreadDemo[29635:5723967] blk3---reading
2016-11-04 17:36:02.258 ThreadDemo[29635:5723940] blk2---reading
2016-11-04 17:36:02.258 ThreadDemo[29635:5723929] blk1---reading
2016-11-04 17:36:02.258 ThreadDemo[29635:5723968] blk---writing
2016-11-04 17:36:02.259 ThreadDemo[29635:5723940] 1====<__NSGlobalBlock__: 0x102895af0>
2016-11-04 17:36:02.259 ThreadDemo[29635:5723967] 2====<__NSGlobalBlock__: 0x102895b30>
2016-11-04 17:36:02.259 ThreadDemo[29635:5723929] 0====<__NSGlobalBlock__: 0x102895ab0>
2016-11-04 17:36:02.259 ThreadDemo[29635:5723968] 3====<__NSGlobalBlock__: 0x102895b70>
2016-11-04 17:36:02.259 ThreadDemo[29635:5723940] 全部執(zhí)行結(jié)束
2016-11-04 17:36:02.259 ThreadDemo[29635:5723499] done
10. 隊(duì)列的掛起和喚醒
- 隊(duì)列的掛起與喚醒相對(duì)較為簡單笑窜,如果你想對(duì)一個(gè)隊(duì)列中的任務(wù)的執(zhí)行進(jìn)行掛起,那么你就使用
dispatch_suspend()
函數(shù)即可登疗。如果你要喚醒某個(gè)掛起的隊(duì)列排截,那么你就可以使用dispatch_resum()
函數(shù)。這兩個(gè)函數(shù)所需的參數(shù)都是你要掛起或者喚醒的隊(duì)列辐益,鑒于知識(shí)點(diǎn)的簡單性就不做過多的贅述了断傲。
#pragma mark -Dispatch_suspend/Dispatch_resume
- (void)GCDDispatch_suspend_resume{
//系統(tǒng)默認(rèn)生成的,所以無法調(diào)用dispatch_resume()和dispatch_suspend()來控制執(zhí)行繼續(xù)或中斷智政。
dispatch_queue_t queue1 = dispatch_queue_create("queue1", 0);
dispatch_queue_t queue2 = dispatch_queue_create("queue2", 0);
dispatch_group_t group = dispatch_group_create();
dispatch_async(queue1, ^{
for (int i = 0; i < 5; i++) {
NSLog(@"%@-------%d",[NSThread currentThread],i);
sleep(1);
}
});
dispatch_async(queue2, ^{
NSLog(@"task2");
});
dispatch_group_async(group, queue1, ^{
NSLog(@"task1 finished!");
});
dispatch_group_async(group, queue2, ^{
dispatch_suspend(queue1);//掛起
NSLog(@"task2 finished!掛起queue1");
[NSThread sleepForTimeInterval:20.0];
dispatch_resume(queue1);//喚醒隊(duì)列
});
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
dispatch_async(queue1, ^{
NSLog(@"task3");
});
dispatch_async(queue2, ^{
NSLog(@"task4");
});
}
打印結(jié)果:可以先思考一下打印結(jié)果
2016-11-04 17:59:41.219 ThreadDemo[29749:5738141] task2
2016-11-04 17:59:41.219 ThreadDemo[29749:5738138] <NSThread: 0x60000027c380>{number = 4, name = (null)}-------0
2016-11-04 17:59:41.220 ThreadDemo[29749:5738141] task2 finished!掛起queue1
2016-11-04 17:59:42.220 ThreadDemo[29749:5738138] <NSThread: 0x60000027c380>{number = 4, name = (null)}-------1
2016-11-04 17:59:43.223 ThreadDemo[29749:5738138] <NSThread: 0x60000027c380>{number = 4, name = (null)}-------2
2016-11-04 17:59:44.225 ThreadDemo[29749:5738138] <NSThread: 0x60000027c380>{number = 4, name = (null)}-------3
2016-11-04 17:59:45.230 ThreadDemo[29749:5738138] <NSThread: 0x60000027c380>{number = 4, name = (null)}-------4
2016-11-04 18:00:01.220 ThreadDemo[29749:5738141] task1 finished!
2016-11-04 18:00:01.220 ThreadDemo[29749:5738141] task3
2016-11-04 18:00:01.221 ThreadDemo[29749:5738769] task4
11. 信號(hào)量Dispatch Semaphore
當(dāng)并行執(zhí)行的處理更新數(shù)據(jù)時(shí)艳悔,會(huì)產(chǎn)出數(shù)據(jù)不一致的情況,有時(shí)應(yīng)用就會(huì)異常退出女仰〔履辏可以使用Serial Dispatch Queue 和 dispatch_barrier也可以處理這種情況,我們也可以使用信號(hào)量Dispatch Semaphor來更好的處理線程安全和同步的問題疾忍。
Dispatch Semaphore是持有計(jì)數(shù)的信號(hào)乔外。使用計(jì)數(shù)來實(shí)現(xiàn)該等待還是運(yùn)行功能。計(jì)數(shù)為0時(shí)等待一罩,計(jì)數(shù)為1或者大于1時(shí)杨幼,減去1而不是等待,就可以運(yùn)行聂渊。
其實(shí)信號(hào)量就是根據(jù)pv操作來實(shí)現(xiàn)的
- p操作-1 v操作+1
信號(hào)量就是一個(gè)資源計(jì)數(shù)器差购,對(duì)信號(hào)量有兩個(gè)操作來達(dá)到互斥,分別是P和V操作汉嗽。
一般情況是這樣進(jìn)行臨界訪問或互斥訪問的: 設(shè)信號(hào)量值為1欲逃, 當(dāng)一個(gè)進(jìn)程1運(yùn)行時(shí),使用資源饼暑,進(jìn)行P操作稳析,即對(duì)信號(hào)量值減1,也就是資源數(shù)少了1個(gè)弓叛。這是信號(hào)量值為0彰居。系統(tǒng)中規(guī)定當(dāng)信號(hào)量值為0是,必須等待撰筷,直到信號(hào)量值不為零才能繼續(xù)操作陈惰。 這時(shí)如果進(jìn)程2想要運(yùn)行,那么也必須進(jìn)行P操作毕籽,但是此時(shí)信號(hào)量為0抬闯,所以無法減1,即不能P操作影钉,也就阻塞画髓。這樣就到到了進(jìn)程1排他訪問。 當(dāng)進(jìn)程1運(yùn)行結(jié)束后平委,釋放資源奈虾,進(jìn)行V操作。資源數(shù)重新加1廉赔,這是信號(hào)量的值變?yōu)?. 這時(shí)進(jìn)程2發(fā)現(xiàn)資源數(shù)不為0肉微,信號(hào)量能進(jìn)行P操作了,立即執(zhí)行P操作蜡塌。信號(hào)量值又變?yōu)?.次數(shù)進(jìn)程2咱有資源碉纳,排他訪問資源。 這就是信號(hào)量來控制互斥的原理
信號(hào)量為0則阻塞線程馏艾,大于0則不會(huì)阻塞劳曹。則我們通過改變信號(hào)量的值奴愉,來控制是否阻塞線程,從而達(dá)到線程同步铁孵。
- (void)GCDDispatchSemaphore{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//創(chuàng)建一個(gè)信號(hào)量dispatch
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
NSMutableArray *array = [NSMutableArray new];
for (int i = 0; i < 10; i++) {
dispatch_async(queue, ^{
//一直等待信號(hào)量大于0
dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, DISPATCH_TIME_FOREVER));
//進(jìn)行排他控制的處理代碼...
//將dispatch semphore的計(jì)數(shù)器減1
[array addObject:[NSNumber numberWithInteger:i]];
//排他控制處理結(jié)束
//將dispatch semphore的計(jì)數(shù)器加1
//如果有通過dispatch_semaphore_wait函數(shù)dispatch semphore的計(jì)數(shù)值增加的線程锭硼,等待就由最先等待的線程執(zhí)行
dispatch_semaphore_signal(semaphore);
});
NSLog(@"%@",array);
}
}
- 創(chuàng)建一個(gè)信號(hào)量dispatch
dispatch_semaphore_t dispatch_semaphore_create(long value);
- 等待信號(hào)量
longdispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout);
返回值和dispatch_group_wait
函數(shù)相同,也可以通過下面進(jìn)行分支處理:
long result = dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10*NSEC_PER_SEC)));
if (result == 0){
//進(jìn)行排他控制的處理代碼...
//將dispatch semphore的計(jì)數(shù)器減1
[array addObject:[NSNumber numberWithInteger:i]];
//排他控制處理結(jié)束
//將dispatch semphore的計(jì)數(shù)器加1
//如果有通過dispatch_semaphore_wait函數(shù)dispatch semphore的計(jì)數(shù)值增加的線程蜕劝,等待就由最先等待的線程執(zhí)行
dispatch_semaphore_signal(semaphore);
}else{
//這個(gè)時(shí)候計(jì)數(shù)值為0檀头,在達(dá)到指定時(shí)間為止還是等待狀態(tài)。
//處理邏輯....
}
- 在進(jìn)行排他處理結(jié)束時(shí)岖沛,通過
dispatch_semaphore_signal
來講計(jì)數(shù)值加1
GCD總結(jié)
- 開不開線程由執(zhí)行任務(wù)的函數(shù)決定
- 異步開暑始,異步是多線程的代名詞
- 同步不開
- 開幾條線程由隊(duì)列決定
- 串行隊(duì)列開一條線程(GCD會(huì)開一條,NSOperation Queue最大并發(fā)數(shù)為1時(shí)也可能開多條)
- 并發(fā)隊(duì)列開多條線程婴削,具體能開的線程數(shù)量由底層線程池決定
- GCD的使用步驟
- 1.創(chuàng)建block任務(wù)
- 2.創(chuàng)建GCD隊(duì)列(串行和并發(fā))
- 3.把block任務(wù)放到GCD隊(duì)列里廊镜,以異步或者同步方式執(zhí)行GCD隊(duì)列
結(jié)尾:
能看到這里的小伙伴都是真愛啊,內(nèi)容太多了馆蠕。學(xué)完這個(gè)你們多思考一下里面方法的聯(lián)系以及實(shí)現(xiàn)期升,好了今天的GCD就講到這里,中間有什么錯(cuò)誤歡迎你們批評(píng)指出!下一篇博客將帶你走進(jìn)NSOperation互躬。
喜歡的話就請點(diǎn)個(gè)喜歡加個(gè)關(guān)注_(樓主好無恥安チ蕖)??
參考書籍:Objective-C高級(jí)編程iOS與OS X多線程和內(nèi)存管理