国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

iOS多線程——GCD篇

2019-11-14 18:35:50
字體:
來源:轉載
供稿:網友

什么是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;}

 


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 弥渡县| 玉田县| 清水县| 西盟| 安丘市| 陇川县| 南木林县| 洮南市| 教育| 新密市| 华容县| 广州市| 汝城县| 徐闻县| 日土县| 浮山县| 秦皇岛市| 遂昌县| 喀喇沁旗| 固原市| 云阳县| 神农架林区| 微博| 扎赉特旗| 甘谷县| 敖汉旗| 乐安县| 壤塘县| 长海县| 穆棱市| 安康市| 彭阳县| 河池市| 濮阳市| 华安县| 丹巴县| 屏东县| 徐汇区| 兴义市| 阿拉善盟| 会昌县|