GCD使用介紹

1、概念數組

一、同步異步:
    a、同步 dispatch_sync():同步執行會等待當前任務執行完再向下執行
    b、異步  dispatch_async():不等待當前任務執行完,而是把任務提交後直接向下執行,不等待提交的任務併發

二、隊列
    a、串行隊列:提交到串行隊列的任務會一個一個按順序執行,上一個任務完成後、再執行下一個
    建立方式(2種同樣):
                一、dispatch_queue_create("tongbu", NULL)
                二、dispatch_queue_create("tongbu", DISPATCH_QUEUE_SERIAL);
                         參數1:隊列標籤 參數2:隊列類型(併發)
                三、dispatch_get_main_queue() 主隊列也是串行隊列
    b、併發隊列:提交到併發隊列的任務對併發執行,每一個任務從提交的那一時刻起都會爲它建立一個線
程,且沒法肯定哪個任務先完成。
     建立方式(2種同樣):
                一、dispatch_get_global_queue(0, 0)//獲取系統的全局併發隊列
                        其中,參數1 有如下可選
                         DISPATCH_QUEUE_PRIORITY_HIGH        //2
                        DISPATCH_QUEUE_PRIORITY_DEFAULT  //0 通常選這個便可
                        DISPATCH_QUEUE_PRIORITY_LOW        //-2
                        DISPATCH_QUEUE_PRIORITY_BACKGROUND // INT16_MIN  ( -32768)     
                二、dispatch_queue_create("tongbu", DISPATCH_QUEUE_CONCURRENT)//本身建立
                        參數1:隊列標籤 參數2:隊列類型(併發)
特別提醒:dispatch_queue_create 每執行一次就會建立一個新對象,
                dispatch_queue_t queue1 =  dispatch_queue_create("tongbu", NULL);
                dispatch_queue_t queue2=  dispatch_queue_create("tongbu", NULL);
                此時queue1 != queue2

                因此使用時若是想要使用同一隊列,必定要將其存儲起來
!併發隊列 執行時,並不必定會將添加到隊列的任務所有一塊兒執行,而是處理數量取決於系統的狀態(CPU核數,負載。。)先執行前幾個,好比一次性添加了10000個任務到併發隊列,他可能因爲負載緣由只併發執行了第40個,當根據執行狀況再併發後續任務app

2、使用
    同步異步與隊列結合使用異步

    連續添加十個任務
    組合1:同步 + 串行    

                無心義,連續添加十個任務,會加一個執行一個,第一個執行完,執行加入第二個
    組合2:異步 + 串行

                十個任務是按順序添加,可是因爲是異步添加,不會影響 "結束"的執行,同時,隊列時串行隊列,因此會挨個執行
    組合3:同步 + 併發

            無心義,覺得他會等待添加的任務完成在繼續下一步
    組合4:異步 + 併發

每一個任務都會開啓新線程去併發執行,至關因而個任務同時併發執行,且不會阻塞當前程序async

3、函數方法
   一、 dispatch_barrier_async函數

dispatch_queue_t queue = dispatch_queue_create("tongbu", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, readFile);
    dispatch_async(queue, readFile);
    //會等上面提交的任務完成後再去寫,寫完後才繼續執行下面的提交任務,防止了讀寫競爭
    dispatch_barrier_async(queue, writeFile);
    
    dispatch_async(queue, readFile);
    dispatch_async(queue, readFile);

這樣,多個read不會互相影響,提升了讀性能,且不影響寫操做(注意上面的是併發隊列)性能

二、掛起/恢復
    注意:它的原理相似於引用計數,一個queue若是調用N次dispatch_suspend,那麼要想恢復,就須要調用N次dispatch_resume才能夠繼續,並且dispatch_resume函數不能隨意調用,只有當前隊列被掛起後才能夠對它使用該函數,不然會報錯spa

dispatch_queue_t queue =  dispatch_queue_create("tongbu", NULL);
    dispatch_suspend(queue);//掛起隊列
    dispatch_resume(queue);//恢復隊列

三、定時器線程

//dispatchQueue:該定時器任務在哪一個隊列執行
    //intervalInSeconds: 間隔時間
    //leewayInSeconds :設置爲0便可 
    dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, <#dispatchQueue#>);
    dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, <#intervalInSeconds#> * NSEC_PER_SEC, <#leewayInSeconds#> * NSEC_PER_SEC);
    dispatch_source_set_event_handler(timer, ^{
         //do something ...
    });
    //一次暫停對應一次開始,默認建立完成timer時是暫停的,原理見上一節
    //開始(不暫停時不能隨意調用)
    dispatch_resume(timer);
    //暫停
    dispatch_suspend(timer);
    //銷燬
    dispatch_source_cancel(_timer);

須要注意:要持有 timer 和 queue,不能讓其銷燬,不然定時器失效。

四、dispatch_semaphore_t 信號量
異步的向數組中添加對象會產生內存問題,須要進行鎖處理,可使用dispatch_semaphore_t信號量機制實現code

- (void)test1 {
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);//併發隊列
    NSMutableArray *array = [[NSMutableArray alloc] init];
    
    for (int i = 0; i < 10000; ++i) {
        dispatch_async(queue, ^{
            [array addObject:[NSNumber numberWithInteger:i]];//這裏會產生內存問題
        });
    }
    NSLog(@"完成");
}

使用dispatch_semaphore_t

- (void)test2 {
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    NSMutableArray *array = [[NSMutableArray alloc] init];
    //信號量
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
    for (int i = 0; i < 10000; ++i) {
        dispatch_async(queue, ^{
            
            //一、該函數會阻塞,等待直到semaphore計數 >= 1, 而後 內部將計數減1,而後該函數執行完返回
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            
            //二、執行到此處時, semaphore計數爲0,表明沒有線程修改array
            [array addObject:[NSNumber numberWithInteger:i]];
            
            //三、處理結束,修改信號量semaphore 加1,若是有dispatch_semaphore_wait函數等待,那麼最早等待的那個線程就先執行
            dispatch_semaphore_signal(semaphore);
            
        });
    }
    NSLog(@"完成");
}

dispatch_semaphore_t,是一個持有計數的信號

//建立信號 設置信號量總數
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(5);
    
    //釋放一個信號,semaphore信號計數 +1
    dispatch_semaphore_signal(semaphore);
    
    //等待信號,當信號計數 >= 1 時就能夠繼續向下執行,同時 它將計數 進行減1 操做,,不然一直等待
    //參數2 爲超時時間,
    //函數返回result: 0 表明success 信號計數 >=1, 非0 表明超時了,信號計數 <1
    long result = dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

適用於有限資源的訪問限制
五、Group

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(@"任務1");
    });
    dispatch_group_async(group, queue, ^{
        NSLog(@"任務2");
    });
    dispatch_group_async(group, queue, ^{
        NSLog(@"任務3");
        [NSThread sleepForTimeInterval:5];
    });
    //任務1,2,3都執行完後才執行該任務
    dispatch_group_notify(group, queue, ^{
        NSLog(@"最後打印");
    });
    
    dispatch_time_t time =  dispatch_time(DISPATCH_TIME_NOW, 10 * NSEC_PER_SEC);
    //wait函數會阻塞當前線程,直到超時或者group提早執行完成,也能夠將等待時間設置爲DISPATCH_TIME_NOW,當即返回結果,不會阻塞
    // result: 0 表明已完成, 非0 未完成,已超時
    long result = dispatch_group_wait(group, time);
    NSLog(@"%ld", result);

六、dispatch_apply

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    //按指定次數將block追加到queue
    //會阻塞當前線程,等待任務完成
    dispatch_apply(10, queue, ^(size_t i) {
        NSLog(@"%zu", i);
    });
    
    NSLog(@"最後打印");
相關文章
相關標籤/搜索