iOS多線程——GCD篇,iosgcd

來源:互聯網
上載者:User

iOS多線程——GCD篇,iosgcd

什麼是GCD

GCD是蘋果對多線程編程做的一套新的抽象基於C語言層的API,結合Block簡化了多線程的操作,使得我們對線程操作能夠更加的安全高效。

在GCD出現之前Cocoa架構提供了NSObject類的

performSelectorInBackground:withObject

performSelectorOnMainThread

方法來簡化多線程編程技術。

GCD可以解決以下多線程編程中經常出現的問題:
1.資料競爭(比如同時更新一個記憶體位址)

2.死結(互相等待)

3.太多線程導致消耗大量記憶體

在iOS中,如果把需要消耗大量時間的操作放在主線程上面,會妨礙主線程中被稱為RunLoop的主迴圈的執行,從而導致不能更新使用者介面、應用程式的畫面長時間停滯等問題。

 

Dispatch Queue

Dispatch Queue是GCD中對於任務的抽象隊列(FIFO)執行處理。

queue分為兩種,

SERIAL_DISPATCH_QUEUE           等待現在執行中處理結束

CONCURRENT_DISPATCH_QUEUE       不等待現在執行中處理結束

換句話說也就是 SERIAL_DISPATCH_QUEUE 是串列,CONCURRENT_DISPATCH_QUEUE是並行。

具體到線程上,就是SERIAL_DISPATCH_QUEUE只會創在一個線程來處理工作順序,而CONCURRENT_DISPATCH_QUEUE則會創在多個線程,但是具體建立多少個則是有啟動並執行作業系統根據資源決定的。

所以SERIAL_DISPATCH_QUEUE 中處理的代碼是有序的,而CONCURRENT_DISPATCH_QUEUE中則是無序的,但是相對會更高效一點。

 

API

dispatch_queue_create

用於建立一個任務執行queue

參數列表

const char *label             queue的名稱,作為該queue的唯一標示,改名會在Xcode和Instruments的調試器中直接作為DispatchQueue名稱顯示出來

dispatch_queue_attr_t     設定queue的類型,即ConcurrentQueue還是SerialQueue,NULL則預設為SerialQueue

傳回值

dispatch_queue_t變數

這裡要說一下main_dispatch_queue 和 global_dispatch_queue 這兩種系統提供的,

main_queue通過

dispatch_get_main_queue()

global_queue通過

dispatch_get_global_queue(),global等級分為

HIGH、DEFAULT、LOW、BACKGROUND四種

 

dispatch_async

向指定的queue中添加block操作,非同步執行,屏蔽了多線程的實現細節,自動為我們產生線程執行。

 

dispatch_after

類似延遲函數,可以指定queue來進行延遲操作

    dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 3ull * NSEC_PER_SEC);    dispatch_after(time, dispatch_get_main_queue(), ^{        NSLog(@"等待3秒");    });

 

dispatch_group_notify

對於監聽queue的執行,當所有任務完成後可以進行回調操作

    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");    });    dispatch_group_notify(group, queue, ^{        NSLog(@"finish");    });

對於一系列的block在同一queue中執行,如果是serialQueue是順序進行的,因此可以在最後一個任務來處理結束操作。但是對於concurrentQueue是並行的,如果想監聽完結操作,就要用該方法。

dispatch_group_wait和notify差不多,只不過wait方法可以設定等待時間。如果時間到了還沒有結束queue的所有操作,那麼接下來還是會繼續進行,不過還是可以設定為forever一直等待下去,這樣就和notify起到一樣的作用。

 

dispatch_barrier_async

該操作主要是為了防止資源競爭。在concurrentQueue中,所有block無序的按照所建立的線程數量同時進行。如果在concurrentQueue中有兩個寫入操作,而且他都是讀取操作,這時兩個寫入操作間就會出現資源競爭,而讀取操作則會讀取髒資料。所以對於在concurrentQueue中不能夠與其它操作並行的block就需要使用dispatch_barrier_async方法來防止資源競爭。

 

dispatch_sync

和dispatch_async不同,dispatch_sync用於線程之間的同步操作,比如說A線程要做一件事必須要放在B線程之後來進行,那麼此時就需要用到dispatch_sync。

另外,不能夠在某個執行線程中同步自己,這樣會造成線程死結,比如說

    dispatch_queue_t queue1 = dispatch_get_main_queue();    dispatch_sync(queue1, ^{        NSLog(@"main queue 中同步main queue操作");    });        dispatch_queue_t queue = dispatch_queue_create("com.queue.www", NULL);    dispatch_async(queue, ^{        dispatch_sync(queue, ^{            NSLog(@"在新的serial queue中同步serial queue操作");        });    });

所以說使用serial queue的時候一定不要同步自己。

 

dispatch_apply

dispatch_apply函數是dispatch_sync和dispatch group的關聯函數,是用指定的次數將指定的Block追加到指定的Dispatch Queue中,並等待全部處理執行結束,例如

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);    dispatch_apply(10, queue, ^(size_t index) {        NSLog(@"%ld",index);    });    NSLog(@"apply finish");2015-08-02 09:38:18.296 Dispatch[7388:2035125] 42015-08-02 09:38:18.296 Dispatch[7388:2035244] 22015-08-02 09:38:18.296 Dispatch[7388:2035241] 12015-08-02 09:38:18.296 Dispatch[7388:2035259] 62015-08-02 09:38:18.296 Dispatch[7388:2035243] 02015-08-02 09:38:18.296 Dispatch[7388:2035257] 32015-08-02 09:38:18.296 Dispatch[7388:2035258] 52015-08-02 09:38:18.296 Dispatch[7388:2035260] 72015-08-02 09:38:18.296 Dispatch[7388:2035125] 82015-08-02 09:38:18.296 Dispatch[7388:2035244] 92015-08-02 09:38:18.296 Dispatch[7388:2035125] apply finish

實際上可以看出來,該函數讓主線程和queue進行同步操作,並且等queue中所有線程執行完畢後才繼續執行。

 

dispatch_semaphore

在進行資料處理時,dispatch_barrier_async可以避免這類問題,但是有時需要更加精細的操作。

比如要對數組添加10000個對象,用concurrentQueue添加。我們知道concurrentQueue會產生多個線程,很可能會出現多個線程一起對數組訪問的情況,很容易出現問題。我們需要控制一次只讓一個線程運算元組,如下:

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);    dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);        NSMutableArray *array = [NSMutableArray new];    for (int i =  0 ; i < 10000 ; i++)    {        dispatch_async(queue, ^{            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);            [array addObject:[NSNumber numberWithInt:i]];            NSLog(@"add %d",i);            dispatch_semaphore_signal(semaphore);        });    }

這裡簡單說一下訊號量,也就是建立dispatch_semaphore的第二個參數。指定一個訊號量,那麼當訊號量是大於0的時候所有線程都是可訪問的。一旦有現成訪問訊號量會減1,如果訊號量為0就會進入等待,知道dispatch_semaphore_signal函數調用來重新恢複訊號量。所以基本上可以理解為有幾個訊號量就能有幾個線程並發的訪問。

再比如說現在有兩個線程一個添加資料一個刪除資料,那麼就需要兩個訊號量變數來實現多線程間的協作

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);    dispatch_semaphore_t semaphoreAdd = dispatch_semaphore_create(1);    dispatch_semaphore_t semaphoreRemove = dispatch_semaphore_create(0);    NSMutableArray *array = [NSMutableArray new];    for (int i =  0 ; i < 2 ; i++)    {        dispatch_async(queue, ^{            dispatch_semaphore_wait(semaphoreAdd, DISPATCH_TIME_FOREVER);            [array addObject:[NSNumber numberWithInt:i]];            NSLog(@"add %lu",[array count]);            dispatch_semaphore_signal(semaphoreRemove);        });        dispatch_async(queue, ^{            dispatch_semaphore_wait(semaphoreRemove, DISPATCH_TIME_FOREVER);            [array removeObject:[NSNumber numberWithInt:i]];            NSLog(@"add %lu",[array count]);            dispatch_semaphore_signal(semaphoreAdd);        });    }

 

 

dispatch_once

dispatch_once用來標記一個操作,只執行一次,該方法一般在生產單例對象使用。如果不用dispatch_once建立單例是不安全的,需要進行加鎖處理,但是dispatch_once可以很好地解決這一點。

+(instancetype)sharedInstance{    static CustomObject *obj;    static dispatch_once_t once;    dispatch_once(&once, ^{        obj = [[CustomObject alloc] init];    });    return obj;}

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.