1. 程式人生 > >iOS-GCD多執行緒程式設計詳解1

iOS-GCD多執行緒程式設計詳解1

文明看博轉載是對自己的尊重也是對學者的鼓勵,歡迎討論

iOS-GCD多執行緒程式設計詳解

一.前言

前面的多執行緒程式設計中分別講到NSThread和NSOperation的多執行緒程式設計,本張主要是講述GCD的程式設計,GCD的多執行緒程式設計是基於BLock或者函式包裹多執行緒任務,由系統管理執行緒實現的,因此其低耦合,容易使用,又是基於C語言實現,執行速度快,是官方推薦的多執行緒實現的首先方案,至於個人什麼順手就用什麼。

二.GCD多執行緒使用說明

在多執行緒程式設計中,首先要考慮的問題是多執行緒任務寫在什麼地方,同步還是非同步,是在主執行緒中執行還是在子執行緒中執行,多執行緒任務的依賴關係,執行的先後順序,是自己建立執行緒還是系統的執行緒承載執行緒任務的執行,是自己管理執行緒還是系統管理,對於GCD而言,多執行緒任務通過Block或者函式來包含多執行緒任務,它的依賴和執行順序有特定的GCD函式,它的任務承載執行緒是有系統生成和管理,所以使用者只需要關心多執行緒任務是使用block還是函式包裹,是使用同步還是非同步,是在主執行緒上執行還是在子執行緒上執行。

1.dispathc_sync:

該函式的作用是提交一個block到指定的dispatch_queue中,直到block執行結束返回,在主執行緒中使用該函式就會造成UI卡住:

note:下面這段程式碼是在主執行緒中呼叫

NSLog(@"before dispatch_sync");<span style="white-space:pre">				</span>//主執行緒中呼叫
    dispatch_sync(dispatch_get_main_queue(), ^{
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"hello world");<span style="white-space:pre">	</span>//這條語句沒有被執行
        });
    });
執行結果:

2015-01-03 17:45:58.213 GCDTest[1750:140657] before dispatch_sync(還有就是介面卡死了,因為形成了死鎖)

note:下面的這段程式碼是在非主執行緒中呼叫:

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    [NSThread detachNewThreadSelector:@selector(netThread:) toTarget:self withObject:@"new thread"];  //子執行緒分支
    NSLog(@"hello world main");
    
}
-(void)netThread:(id)sender{
    NSLog(@"before dispatch_sync");
    dispatch_sync(dispatch_get_main_queue(), ^{<span style="white-space:pre">			</span>//相當於在主執行緒中呼叫dispatch_sync
        dispatch_sync(dispatch_get_main_queue(), ^{
            NSLog(@"hello world subThread");<span style="white-space:pre">	</span>//從結果中看出這條語句沒有被執行
        });
    });
}
@end

執行結果:

2015-01-04 17:37:04.426 GCDTest[1869:155469] before dispatch_sync(螢幕卡死)

2015-01-04 17:37:04.426 GCDTest[1869:155423] hello world main

所以在使用disatich_sync時不要在UI執行緒使用。

相似函式:

dispatch_sync_f:該函式提交的是一個函式任務,相當於dispatch_sync:提交block,說白了把提交的function相當於block,有興趣的可以看我其中的一篇BLock揭祕,瞭解函式和block的一些對映個人思想。

 dispatch_async_f(dispatch_get_main_queue(), nil, fun_my);
    
}

static void fun_my(void *hel){
    NSLog(@"function");
}
執行結果:

2015-01-04 00:53:48.894 GCDTest[2010:161173] function   

在主執行緒中使用的dispatch_sync(dispatch_get_main_queue,^{})形成死鎖圖解:


dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"我是非同步的block1,我被裝在dispatch_get_main_queue中");
    });
    
    NSLog(@"我是主執行緒,我的原始碼位置被寫在block1的後面");

執行結果:

2015-01-04 22:37:31.821 GCDTest[713:28383] 我是主執行緒,我的原始碼位置被寫在block1的後面

2015-01-04 22:37:31.836 GCDTest[713:28383] 我是非同步的block1,我被裝在dispatch_get_main_queue

圖解分析:



三.各個GCD函式使用詳解

通過上一節的簡單使用,我們可以把GCD分解為執行緒任務包裝:block,function,執行緒任務的容器:dispatch_queue(序列型別和併發型別),同步和非同步(重點是非同步的實現);block可以參考點選開啟連結,function就是一般的函式,同步和非同步就是同步執行和非同步執行,下面通過程式碼來了解block的容器-------dispatch_queue.

1.dispatch_global_queue

dispatch_group_t group2 = dispatch_group_create();
    dispatch_group_async(group2, dispatch_get_global_queue(0, 0), ^{
        NSLog(@"*block1 執行線上程%@",[NSThread currentThread]);
    });
    
    dispatch_group_async(group2, dispatch_get_global_queue(0, 0), ^{
        NSLog(@"*block2 執行線上程%@",[NSThread currentThread]);
    });
    
    dispatch_group_async(group2, dispatch_get_global_queue(0, 0), ^{
        NSLog(@"*block3 執行線上程%@",[NSThread currentThread]);
    });
    
    dispatch_group_async(group2, dispatch_get_global_queue(0, 0), ^{
        NSLog(@"*block4 執行線上程%@",[NSThread currentThread]);
    });
    
    dispatch_group_async(group2, dispatch_get_global_queue(0, 0), ^{
        NSLog(@"*block5 執行線上程%@",[NSThread currentThread]);
    });

執行結果:

1:

2015-01-04 23:04:37.273 GCDTest[850:36850] *block2 執行線上程<NSThread: 0x7fc2d9c6e350>{number = 5, name = (null)}

2015-01-04 23:04:37.273 GCDTest[850:36848] *block3 執行線上程<NSThread: 0x7fc2d9c6b200>{number = 3, name = (null)}

2015-01-04 23:04:37.273 GCDTest[850:36849] *block4 執行線上程<NSThread: 0x7fc2d9f269a0>{number = 4, name = (null)}

2015-01-04 23:04:37.274 GCDTest[850:36854] *block5 執行線上程<NSThread: 0x7fc2d9c6d180>{number = 6, name = (null)}

2015-01-04 23:04:37.273 GCDTest[850:36847] *block1 執行線上程<NSThread: 0x7fc2d9d1ce30>{number = 2, name = (null)}

2:

2015-01-04 23:07:09.728 GCDTest[858:37701] *block2 執行線上程<NSThread: 0x7fc569406f40>{number = 4, name = (null)}

2015-01-04 23:07:09.728 GCDTest[858:37700] *block3 執行線上程<NSThread: 0x7fc56940da90>{number = 5, name = (null)}

2015-01-04 23:07:09.728 GCDTest[858:37698] *block1 執行線上程<NSThread: 0x7fc5694182a0>{number = 2, name = (null)}

2015-01-04 23:07:09.728 GCDTest[858:37699] *block4 執行線上程<NSThread: 0x7fc56952c740>{number = 3, name = (null)}

2015-01-04 23:07:09.728 GCDTest[858:37704] *block5 執行線上程<NSThread: 0x7fc569713820>{number = 6, name = (null)}

。。。

執行結果每次都不同,所在的執行執行緒也不同,所以dispatch_global_queue是並行的系統維護的執行緒依次衝佇列中取出block執行

2.dispatch_main_queue

dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, dispatch_get_main_queue(), ^{
        NSLog(@"block1 執行線上程%@",[NSThread currentThread]);
    });
    
    dispatch_group_async(group, dispatch_get_main_queue(), ^{
        NSLog(@"block2 執行線上程%@",[NSThread currentThread]);
    });
    
    dispatch_group_async(group, dispatch_get_main_queue(), ^{
        NSLog(@"block3 執行線上程%@",[NSThread currentThread]);
    });
    
    dispatch_group_async(group, dispatch_get_main_queue(), ^{
        NSLog(@"block4 執行線上程%@",[NSThread currentThread]);
    });
    
    dispatch_group_async(group, dispatch_get_main_queue(), ^{
        NSLog(@"block5 執行線上程%@",[NSThread currentThread]);
    });

執行結果:

2015-01-04 23:07:09.762 GCDTest[858:37660] block1 執行線上程<NSThread: 0x7fc569613060>{number = 1, name = main}

2015-01-04 23:07:09.762 GCDTest[858:37660] block2 執行線上程<NSThread: 0x7fc569613060>{number = 1, name = main}

2015-01-04 23:07:09.762 GCDTest[858:37660] block3 執行線上程<NSThread: 0x7fc569613060>{number = 1, name = main}

2015-01-04 23:07:09.762 GCDTest[858:37660] block4 執行線上程<NSThread: 0x7fc569613060>{number = 1, name = main}

2015-01-04 23:07:09.763 GCDTest[858:37660] block5 執行線上程<NSThread: 0x7fc569613060>{number = 1, name = main}

執行結果每次都是一致的,說明dispatch_main_queue是根據其加入順序執行的執行的執行緒為主執行緒;

所以順序佇列和並行佇列的對比圖如下:


小結:這篇博文主要說了關於順序佇列和並行佇列的block容器的特性,後面將會陸續的對GCD的多執行緒程式設計有詳細的使用。

引用或者轉載請註明出處,是對自己的尊重也是對學者的鼓勵。