Grand Central Dispatch(GCD)是 Apple 開發的一個多核編程的解決方法。它是一套純 C 語言的 API
,主要用於優化應用程序以支持多核處理器以及其餘對稱多處理系統。它是一個在線程池模式的基礎上執行的併發任務。編程
任務即執行操做
,就是線程中須要執行的代碼。在GCD
中就是放在block
中執行的代碼都是任務。任務分爲同步任務(sync)
和異步任務(async)
。markdown
同步任務(sync)
:同步添加到隊列當中,當前面的任務沒有執行完畢時會一直等待,直到前面的任務執行完畢纔會執行當前加入的任務。不能夠在新的線程中執行,不具有開闢新的線程能力。異步任務(async)
:異步添加到隊列當中,無需等待前面的任務執行完成才執行,加入隊列就會執行。能夠在新的線程中執行,具有開闢新的線程能力。注意:具有開啓新線程的能力不表明必定開啓新的線程
指執行任務的隊列,就是等待執行的任務列表,遵循先進先出IFFO
原則。在GCD中有串行隊列(Serial Dispatch Queue)
和並行隊列(Concurrent Dispatch Queue),又叫併發隊列
。併發
串行隊列(Serial Dispatch Queue)
:只開啓一個線程
,每次只有一個任務執行,任務執行完成後纔會執行下一個任務。並行隊列(Concurrent Dispatch Queue)
:可讓多個任務同時執行,能夠開啓多個線程來執行多個任務。注意:併發隊列只有在異步函數下才有效
。//第一個參數是隊列的名字,自定義;第二個參數表示是串行仍是併發
//DISPATCH_QUEUE_SERIAL = NULL,所以DISPATCH_QUEUE_SERIAL能夠用NULL代替建立串行隊列
dispatch_queue_t queue = dispatch_queue_create("shifx", DISPATCH_QUEUE_SERIAL);
複製代碼
//第一個參數是隊列的名字,自定義;第二個參數表示是串行仍是併發
dispatch_queue_t queue = dispatch_queue_create("shifx", DISPATCH_QUEUE_CONCURRENT);
複製代碼
//建立同步任務(queue是隊列)
dispatch_sync(queue, ^{
});
複製代碼
//建立異步任務(queue是隊列)
dispatch_async(queue, ^{
});
複製代碼
綜上所述,咱們能夠得出一共四種組合外加兩種特殊的隊列,即異步
-(void)serialSysncText {
//串行隊列
dispatch_queue_t serial = dispatch_queue_create("shifx", DISPATCH_QUEUE_SERIAL);
NSLog(@"串行同步任務開始");
dispatch_sync(serial, ^{
sleep(1);
for (int i = 0; i<3; i++) {
NSLog(@"串行同步任務1 = %d",i);
}
});
dispatch_sync(serial, ^{
sleep(1);
for (int i = 0; i<3; i++) {
NSLog(@"串行同步任務2 = %d",i);
}
});
NSLog(@"串行同步任務結束");
}
複製代碼
從運行結果當中,咱們能夠看到串行隊列中的同步任務都是按照前後順序依次執行的。async
-(void)concurrentAsysncText {
//併發隊列
dispatch_queue_t concurrent = dispatch_queue_create("shifx", DISPATCH_QUEUE_CONCURRENT);
NSLog(@"併發同步任務開始");
dispatch_sync(concurrent, ^{
sleep(1);
for (int i = 0; i<3; i++) {
NSLog(@"併發同步任務1 = %d",i);
}
});
dispatch_sync(concurrent, ^{
sleep(1);
for (int i = 0; i<3; i++) {
NSLog(@"併發同步任務2 = %d",i);
}
});
NSLog(@"併發同步任務結束");
}
複製代碼
從結果得知,併發隊列執行的同步任務也是
按照順序依次執行
的,由於它們都在主線程中執行
的,沒有開啓新的線程。感興趣的小夥伴能夠打印下線程看下。函數
-(void)serialAsysncText {
//串行隊列
dispatch_queue_t serial = dispatch_queue_create("shifx", DISPATCH_QUEUE_SERIAL);
NSLog(@"串行異步任務開始");
dispatch_async(serial, ^{
for (int i = 0; i<3; i++) {
sleep(1);
NSLog(@"串行異步任務1 = %d",i);
NSLog(@"當前線程:%@",[NSThread currentThread]);
}
});
dispatch_async(serial, ^{
for (int i = 0; i<3; i++) {
sleep(1);
NSLog(@"串行異步任務2 = %d",i);
NSLog(@"當前線程:%@",[NSThread currentThread]);
}
});
NSLog(@"串行異步任務結束");
}
複製代碼
從運行結果能夠看出,優化
-(void)concurrentAsysncText {
//併發隊列
dispatch_queue_t concurrent = dispatch_queue_create("shifx", DISPATCH_QUEUE_CONCURRENT);
NSLog(@"併發異步任務開始");
dispatch_async(concurrent, ^{
for (int i = 0; i<3; i++) {
sleep(1);
NSLog(@"併發異步任務1 = %d",i);
NSLog(@"當前線程:%@",[NSThread currentThread]);
}
});
dispatch_async(concurrent, ^{
for (int i = 0; i<3; i++) {
sleep(1);
NSLog(@"併發異步任務2 = %d",i);
NSLog(@"當前線程:%@",[NSThread currentThread]);
}
});
NSLog(@"併發異步任務結束");
}
複製代碼
從運行結果來看,spa
因爲主隊列是串行隊列,它不能在主線程中調用主隊列同步任務,以下所示崩潰緣由就是同步任務放在了主線程中,須要等待主線程執行完畢才能夠,而主線程須要等待該方法執行完成,
二者互相等待形成死鎖
,因此崩潰了。線程
代碼3d
//使用 NSThread 的 detachNewThreadWithBlock 方法會建立線程
[NSThread detachNewThreadWithBlock:^{
[self mainSysncText];
}];
-(void)mainSysncText {
NSLog(@"當前所在的線程:%@",[NSThread currentThread]);
dispatch_sync(dispatch_get_main_queue(), ^{
for (int i = 0; i<2; i++) {
sleep(1);
NSLog(@"主隊列同步任務1 = %d",i);
NSLog(@"當前線程:%@",[NSThread currentThread]);
}
});
dispatch_sync(dispatch_get_main_queue(), ^{
for (int i = 0; i<2; i++) {
sleep(1);
NSLog(@"主隊列同步任務2 = %d",i);
NSLog(@"當前線程:%@",[NSThread currentThread]);
}
});
}
複製代碼
執行結果
因爲主隊列是串行隊列,因此主隊列+異步任務
就至關於串行隊列+異步任務
-(void)mainAsysncText {
NSLog(@"當前所在的線程:%@",[NSThread currentThread]);
NSLog(@"主隊列異步任務開始");
dispatch_async(dispatch_get_main_queue(), ^{
for (int i = 0; i<2; i++) {
sleep(1);
NSLog(@"主隊列異步任務1 = %d",i);
NSLog(@"當前線程:%@",[NSThread currentThread]);
}
});
dispatch_async(dispatch_get_main_queue(), ^{
for (int i = 0; i<2; i++) {
sleep(1);
NSLog(@"主隊列異步任務2 = %d",i);
NSLog(@"當前線程:%@",[NSThread currentThread]);
}
});
NSLog(@"主隊列異步任務結束");
}
複製代碼
效果等同於
串行隊列+異步任務