iOS開發(fā) 多線程的高級應用(一)

在iOS開發(fā)的道路上,多線程的重要性不言而喻. 大部分我們都停留在基礎的使用上面.缺乏高級應用. 缺乏提升,是因為我們面對他太少,復雜的事情重復做,復雜的事務基礎化. 差距就是這樣拉開了 ------- 偉大的樓主

言歸正傳: 今天講講GCD的高級應用之信號量篇

一, 信號量的本質(zhì):
信號量的本質(zhì)是數(shù)據(jù)操作鎖, 它本身不具有數(shù)據(jù)交換的功能,而是通過控制其他的通信資源來實現(xiàn)進程間通信,它本身只是一種外部資源的標識。信號量在此過程中負責數(shù)據(jù)操作的互斥、同步等功能.

二: 信號量的工作原理

由于信號量只能進行兩種操作等待和發(fā)送信號,即P(sv)和V(sv),他們的行為是這樣的:
P(sv):如果sv的值大于零,就給它減1;如果它的值為零,就掛起該進程的執(zhí)行
V(sv):如果有其他進程因等待sv而被掛起,就讓它恢復運行,如果沒有進程因等待sv而掛起,就給它加1.

舉個例子,就是 兩個進程共享信號量sv,一旦其中一個進程執(zhí)行了P(sv)操作,它將得到信號量,并可以進入臨界區(qū),使sv減1。而第二個進程將被阻止進入臨界區(qū),因為 當它試圖執(zhí)行P(sv)時,sv為0,它會被掛起以等待第一個進程離開臨界區(qū)域并執(zhí)行V(sv)釋放信號量,這時第二個進程就可以恢復執(zhí)行。

三: iOS中GCD的信號量函數(shù)解析:

dispatch_semaphore_t  semaphore = dispatch_semaphore_create(2);  

這行代碼創(chuàng)建了一個信號量,同時指明了最多有2個資源可以訪問該"臨界區(qū)域"

dispatch_semaphore_signal(semaphore)

這行代碼 提高信號量 , 信號量計數(shù) + 1

dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

這行代碼 降低信號量 , 信號量計數(shù) - 1

特別注意 當信號為0(零),在執(zhí)行 dispatch_semaphore_wait 語句時,信號量計數(shù)小于0 ,阻塞當前線程.

四: GCD的信號量應用場景: 控制最大并發(fā)量, 控制資源的同步訪問,如數(shù)據(jù)訪問,網(wǎng)絡同步加載.

例如我有這樣的一段代碼,假設需求是控制兩個網(wǎng)絡的執(zhí)行順序 如想讓請求一完成之后,在進行網(wǎng)絡請求二,然后在進行網(wǎng)絡請求N (實現(xiàn)的方式有多種多樣)在此處主要討論GCD semaphore 信號量的使用:

首先大家看看這段代碼帶來的問題

-(void)testSemaphore{
  
    NSLog(@"current1:%@",[NSThread currentThread]);
   
    dispatch_semaphore_t  semaphore = dispatch_semaphore_create(0);
   
    [AKkaHttpTool Post:@"https://api.douban.com/v2/book/1220562" parameters:@{@"":@""} success:^(id  _Nullable responseObject) {
        
        dispatch_semaphore_signal(semaphore);
      
    } failure:^(NSError * _Nullable error, NSInteger statusCode) {
        dispatch_semaphore_signal(semaphore);
    }];
    
    NSLog(@"你會來這兒嗎1");
    NSLog(@"current1:%@",[NSThread currentThread]);
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); //等待信號,當信號總量少于0 的時候就會一直等待 ,否則就可以正常的執(zhí)行,并讓信號總量-1

    NSLog(@"你會來這兒嗎2");
    
    [AKkaHttpTool Post:@"https://api.douban.com/v2/book/1220562" parameters:@{@"":@""} success:^(id  _Nullable responseObject) {
        NSLog(@"resqueue2:");
    } failure:^(NSError * _Nullable error, NSInteger statusCode) {
    }];
}

下面我用一張截圖進行說明,主要是用于說明 dispatch_semaphore_wait 會阻塞當前線程


image.png

接下來這三個網(wǎng)絡請求使用GCD信號量實現(xiàn)同步,并且不阻塞主線程

- (IBAction)gcd2:(id)sender {
  
   dispatch_queue_t queue = dispatch_queue_create("AkSemaphore", NULL);
 
   dispatch_async(queue, ^{
      NSLog(@"current1:%@",[NSThread currentThread]);
      dispatch_semaphore_t  semaphore = dispatch_semaphore_create(0);
       
      [AKkaHttpTool Post:@"https://api.douban.com/v2/book/1220562" parameters:@{@"":@""} success:^(id  _Nullable responseObject) {
           
           dispatch_semaphore_signal(semaphore);
           NSLog(@"resqueue1:");
       } failure:^(NSError * _Nullable error, NSInteger statusCode) {
           dispatch_semaphore_signal(semaphore);
       }];
       
       NSLog(@"你會來這兒嗎1");
       
       dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); //等待信號,當信號總量少于0 的時候就會一直等待 ,否則就可以正常的執(zhí)行,并讓信號總量-1
       
       NSLog(@"你會來這兒嗎2");
       
       [AKkaHttpTool Post:@"https://api.douban.com/v2/book/1220562" parameters:@{@"":@""} success:^(id  _Nullable responseObject) {
           NSLog(@"resqueue2:");
           dispatch_semaphore_signal(semaphore);
       } failure:^(NSError * _Nullable error, NSInteger statusCode) {
           dispatch_semaphore_signal(semaphore);
       }];
       
       dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); //等待信號,當信號總量少于0 的時候就會一直等待 ,否則就可以正常的執(zhí)行,并讓信號總量-1
       
        NSLog(@"你會來這兒嗎3");
       [AKkaHttpTool Post:@"https://api.douban.com/v2/book/1220562" parameters:@{@"":@""} success:^(id  _Nullable responseObject) {
           NSLog(@"resqueue3:");   
       } failure:^(NSError * _Nullable error, NSInteger statusCode) {
       }];
    });
}

image.png

接下來講一下控制網(wǎng)絡的并發(fā)訪問 :
假如現(xiàn)在有一個這樣的需求,需要先下載50張圖片, 一般異步會開啟新的線程,但過多的線程 數(shù)與項目的性能是成反比的 . 所以控制并發(fā),提高性能則尤為重要 : 實例代碼如下

- (void)testGCD3{
    dispatch_semaphore_t semaphore =  dispatch_semaphore_create(5);
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    for (int i=0;i<100 ; i++) {
        
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        
        dispatch_async(queue, ^{
            NSLog(@"i = %d",i);
            //此處模擬一個 異步下載圖片的操作
            sleep(2);
            dispatch_semaphore_signal(semaphore);
        });
    }
}

代碼講解如下圖:


image.png
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容