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

首頁 > 系統 > iOS > 正文

iOS多線程GCD的總結

2019-11-06 09:44:48
字體:
來源:轉載
供稿:網友

大家都知道,多線程分為Pthreads、NSThread、GCD和NSOperation & NSOperationQueue四套方案

接下來主要介紹GCD(Grand Central Dispatch) GCD:是蘋果為多核的并行運算提出的解決方案,所以會自動合理地利用更多的CPU內核(比如雙核、四核),最重要的是它會自動管理線程的生命周期(創建線程、調度任務、銷毀線程),完全不需要我們管理,我們只需要告訴干什么就行。同時它使用的也是 c語言,不過由于使用了 Block(Swift里叫做閉包),使得使用起來更加方便,而且靈活。

一、任務和隊列 在 GCD 中,加入了兩個非常重要的概念: 任務 和 隊列。

《1》任務:即操作,在 GCD 中就是一個 Block,所以添加任務十分方便。任務有兩種執行方式: 同步執行 和 異步執行,他們之間的區別是 是否會創建新的線程。 同步(sync) 和 異步(async) 的主要區別在于會不會阻塞當前線程,直到 Block 中的任務執行完畢! 同步(sync) 操作,它會阻塞當前線程并等待 Block 中的任務執行完畢,然后當前線程才會繼續往下運行。 異步(async)操作,當前線程會直接往下執行,它不會阻塞當前線程。

《2》隊列:用于存放任務。一共有兩種隊列, 串行隊列 和 并行隊列。 放到串行隊列的任務,GCD 會 FIFO(先進先出) 地取出來一個,執行一個,然后取下一個,這樣一個一個的執行。 放到并行隊列的任務,GCD 也會 FIFO的取出來,但不同的是,它取出來一個就會放到別的線程,然后再取出來一個又放到另一個的線程。這樣由于取的動作很快,忽略不計,看起來,所有的任務都是一起執行的。不過需要注意,GCD 會根據系統資源控制并行的數量,所以如果任務很多,它并不會讓所有任務同時執行。

《3》總結:串行隊列中:同步執行是在當前線程,一個一個執行;異步執行是在其他線程,一個一個執行 并行隊列中:同步執行是在當前線程,一個一個執行;異步執行是開很多線程,一起執行

二、創建任務

《1》同步任務:會阻塞當前線程 (SYNC)

//OBJECTIVE-C dispatch_sync(<#queue#>, ^{ NSLog(@"%@", [NSThread currentThread]); });//SWIFT dispatch_sync(<#queue#>, { () -> Void in PRintln(NSThread.currentThread()) })

《2》異步任務:不會阻塞當前線程 (ASYNC)

//OBJECTIVE-C dispatch_async(<#queue#>, ^{ //code here NSLog(@"%@", [NSThread currentThread]); });//SWIFT dispatch_async(<#queue#>, { () -> Void in //code here println(NSThread.currentThread()) })

為了更好的理解同步和異步,和各種隊列的使用,下面看兩個示例 示例一:

//主線程調用 swiftNSLog("之前 - %@", NSThread.currentThread())dispatch_sync(dispatch_get_main_queue(), { () -> Void in NSLog("sync - %@", NSThread.currentThread())})NSLog("之后 - %@", NSThread.currentThread())//oc NSLog(@"之前 - %@", [NSThread currentThread]); dispatch_sync(dispatch_get_main_queue(), ^{ NSLog(@"sync - %@", [NSThread currentThread]); });NSLog(@"之后 - %@", [NSThread currentThread]);

輸出結果: 只會打印第一句:之前 - {number = 1, name = main} ,然后主線程就卡死了,你可以在界面上放一個按鈕,你就會發現點不了了。 解釋: 同步任務會阻塞當前線程,然后把 Block 中的任務放到指定的隊列中執行,只有等到 Block 中的任務完成后才會讓當前線程繼續往下運行。 那么這里的步驟就是:打印完第一句后,dispatch_sync 立即阻塞當前的主線程,然后把 Block 中的任務放到 main_queue 中,可是 main_queue 中的任務會被取出來放到主線程中執行,但主線程這個時候已經被阻塞了,所以 Block 中的任務就不能完成,它不完成,dispatch_sync 就會一直阻塞主線程,這就是死鎖現象。導致主線程一直卡死。

示例二:

//swiftlet queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL) NSLog("之前 - %@", NSThread.currentThread()) dispatch_async(queue, { () -> Void in NSLog("sync之前 - %@", NSThread.currentThread()) dispatch_sync(queue, { () -> Void in NSLog("sync - %@", NSThread.currentThread()) }) NSLog("sync之后 - %@", NSThread.currentThread()) }) NSLog("之后 - %@", NSThread.currentThread()) //oc dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL); NSLog(@"之前 - %@", [NSThread currentThread]); dispatch_async(queue, ^{ NSLog(@"sync之前 - %@", [NSThread currentThread]); dispatch_sync(queue, ^{ NSLog(@"sync - %@", [NSThread currentThread]); }); NSLog(@"sync之后 - %@", [NSThread currentThread]); }); NSLog(@"之后 - %@", [NSThread currentThread]);

結果:2017-02-27 20:31:22.438 demo[95573:7473887] 之前 - {number = 1, name = main} 2017-02-27 20:31:22.438 demo[95573:7473887] 之后 - {number = 1, name = main} 2017-02-27 20:31:22.438 demo[95573:7473926] sync之前 - {number = 3, name = (null)}

很明顯 sync - %@ 和 sync之后 - %@ 沒有被打印出來!

原因如下: 使用 DISPATCH_QUEUE_SERIAL 這個參數,創建了一個 串行隊列。 打印出 之前 - %@ 這句。 dispatch_async 異步執行,所以當前線程不會被阻塞,于是有了兩條線程,一條當前線程繼續往下打印出 之后 - %@這句, 另一臺執行 Block 中的內容打印 sync之前 - %@ 這句。因為這兩條是并行的,所以打印的先后順序無所謂。 注意,高潮來了。現在的情況和上一個例子一樣了。dispatch_sync同步執行,于是它所在的線程會被阻塞,一直等到 sync 里的任務執行完才會繼續往下。于是 sync 就高興的把自己 Block 中的任務放到 queue 中,可誰想 queue 是一個串行隊列,一次執行一個任務,所以 sync 的 Block 必須等到前一個任務執行完畢,可萬萬沒想到的是 queue 正在執行的任務就是被 sync 阻塞了的那個。于是又發生了死鎖。所以 sync 所在的線程被卡死了。剩下的兩句代碼自然不會打印。

《3》隊列組 隊列組可以將很多隊列添加到一個組里,這樣做的好處是,當這個組里所有的任務都執行完了,隊列組會通過一個方法通知我們。下面是使用方法,這是一個很實用的功能。

OBJECTIVE-C//1.創建隊列組dispatch_group_t group = dispatch_group_create();//2.創建隊列dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);//3.多次使用隊列組的方法執行任務, 只有異步方法//3.1.執行3次循環dispatch_group_async(group, queue, ^{ for (NSInteger i = 0; i < 3; i++) { NSLog(@"group-01 - %@", [NSThread currentThread]); }});//3.2.主隊列執行8次循環dispatch_group_async(group, dispatch_get_main_queue(), ^{ for (NSInteger i = 0; i < 8; i++) { NSLog(@"group-02 - %@", [NSThread currentThread]); }});//3.3.執行5次循環dispatch_group_async(group, queue, ^{ for (NSInteger i = 0; i < 5; i++) { NSLog(@"group-03 - %@", [NSThread currentThread]); }});//4.都完成后會自動通知dispatch_group_notify(group, dispatch_get_main_queue(), ^{ NSLog(@"完成 - %@", [NSThread currentThread]);});SWIFT//1.創建隊列組let group = dispatch_group_create()//2.創建隊列let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)//3.多次使用隊列組的方法執行任務, 只有異步方法//3.1.執行3次循環dispatch_group_async(group, queue) { () -> Void in for _ in 0..<3 { NSLog("group-01 - %@", NSThread.currentThread()) }}//3.2.主隊列執行8次循環dispatch_group_async(group, dispatch_get_main_queue()) { () -> Void in for _ in 0..<8 { NSLog("group-02 - %@", NSThread.currentThread()) }}//3.3.執行5次循環dispatch_group_async(group, queue) { () -> Void in for _ in 0..<5 { NSLog("group-03 - %@", NSThread.currentThread()) }}//4.都完成后會自動通知dispatch_group_notify(group, dispatch_get_main_queue()) { () -> Void in NSLog("完成 - %@", NSThread.currentThread())}

結果如下: 2017-02-27 20:17:11.583 demo[95330:7457515] group-03 - {number = 4, name = (null)} 2017-02-27 20:17:11.583 demo[95330:7457514] group-01 - {number = 3, name = (null)} 2017-02-27 20:17:11.584 demo[95330:7457515] group-03 - {number = 4, name = (null)} 2017-02-27 20:17:11.585 demo[95330:7457514] group-01 - {number = 3, name = (null)} 2017-02-27 20:17:11.586 demo[95330:7457515] group-03 - {number = 4, name = (null)} 2017-02-27 20:17:11.587 demo[95330:7457514] group-01 - {number = 3, name = (null)} 2017-02-27 20:17:11.587 demo[95330:7457515] group-03 - {number = 4, name = (null)} 2017-02-27 20:17:11.588 demo[95330:7457515] group-03 - {number = 4, name = (null)} 2017-02-27 20:17:11.595 demo[95330:7457402] group-02 - {number = 1, name = main} 2017-02-27 20:17:11.595 demo[95330:7457402] group-02 - {number = 1, name = main} 2017-02-27 20:17:11.596 demo[95330:7457402] group-02 - {number = 1, name = main} 2017-02-27 20:17:11.597 demo[95330:7457402] group-02 - {number = 1, name = main} 2017-02-27 20:17:11.598 demo[95330:7457402] group-02 - {number = 1, name = main} 2017-02-27 20:17:11.599 demo[95330:7457402] group-02 - {number = 1, name = main} 2017-02-27 20:17:11.599 demo[95330:7457402] group-02 - {number = 1, name = main} 2017-02-27 20:17:11.600 demo[95330:7457402] group-02 - {number = 1, name = main} 2017-02-27 20:17:11.601 demo[95330:7457402] 完成 - {number = 1, name = main}

三、創建隊列

《1》主隊列:這是一個特殊的 串行隊列。主隊列用于刷新 UI,任何需要刷新 UI 的工作都要在主隊列執行,所以一般耗時的任務都要放到別的線程執行。

//OBJECTIVE-C dispatch_queue_t queue = ispatch_get_main_queue(); //SWIFT let queue = ispatch_get_main_queue()

《2》自己創建的隊列:既可以自己創建串行隊列, 也可以創建并行隊列。

//OBJECTIVE-C //串行隊列 dispatch_queue_t queue = dispatch_queue_create("tk.bourne.testQueue", NULL); dispatch_queue_t queue = dispatch_queue_create("tk.bourne.testQueue", DISPATCH_QUEUE_SERIAL); //并行隊列 dispatch_queue_t queue = dispatch_queue_create("tk.bourne.testQueue", DISPATCH_QUEUE_CONCURRENT); //SWIFT //串行隊列 let queue = dispatch_queue_create("tk.bourne.testQueue", nil); let queue = dispatch_queue_create("tk.bourne.testQueue", DISPATCH_QUEUE_SERIAL) //并行隊列 let queue = dispatch_queue_create("tk.bourne.testQueue", DISPATCH_QUEUE_CONCURRENT)

其中第一個參數是標識符,用于 DEBUG 的時候標識唯一的隊列,可以為空。第二個參數用來表示創建的隊列是串行的還是并行的,傳入 DISPATCH_QUEUE_SERIAL 或 NULL 表示創建串行隊列。傳入 DISPATCH_QUEUE_CONCURRENT 表示創建并行隊列。

《3》全局并行隊列: 只要是并行任務一般都加入到這個隊列。這是系統提供的一個并發隊列。

//OBJECTIVE-C dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //SWIFT let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)

四、關于GCD,還有兩個需要說的:

func dispatch_barrier_async(_ queue: dispatch_queue_t, _ block: dispatch_block_t):

這個方法重點是你傳入的 queue,當你傳入的 queue 是通過 DISPATCH_QUEUE_CONCURRENT 參數自己創建的 queue 時,這個方法會阻塞這個 queue(注意是阻塞 queue ,而不是阻塞當前線程),一直等到這個 queue 中排在它前面的任務都執行完成后才會開始執行自己,自己執行完畢后,再會取消阻塞,使這個 queue 中排在它后面的任務繼續執行。 如果你傳入的是其他的 queue, 那么它就和 dispatch_async 一樣了。

func dispatch_barrier_sync(_ queue: dispatch_queue_t, _ block: dispatch_block_t):

這個方法的使用和上一個一樣,傳入 自定義的并發隊列(DISPATCH_QUEUE_CONCURRENT),它和上一個方法一樣的阻塞 queue,不同的是 這個方法還會 阻塞當前線程。 如果你傳入的是其他的 queue, 那么它就和 dispatch_sync 一樣了。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 台前县| 东山县| 天气| 修水县| 遵义县| 新密市| 天柱县| 商丘市| 同仁县| 搜索| 正镶白旗| 天峨县| 图木舒克市| 中西区| 壶关县| 锦屏县| 巴中市| 望奎县| 星子县| 高平市| 仁寿县| 济南市| 武胜县| 烟台市| 佛坪县| 孝感市| 阳新县| 贺兰县| 册亨县| 英德市| 周口市| 苗栗县| 望城县| 休宁县| 临江市| 库车县| 文水县| 中牟县| 平阴县| 清徐县| 沅江市|