GCD简介二:多核心的性能
生活随笔
收集整理的這篇文章主要介紹了
GCD简介二:多核心的性能
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
一、概念
為了在單一進(jìn)程中充分發(fā)揮多核的優(yōu)勢,我們有必要使用多線程技術(shù)。在低層,GCD全局dispatch queue僅僅是工作線程池的抽象。這些隊列中的Block一旦可用,就會被dispatch到工作線程中。提交至用戶隊列的Block最終也會通過全局隊列進(jìn)入相同的工作線程池(除非你的用戶隊列的目標(biāo)是主線程,但是為了提高運行速度,我們絕不會這么干)。
有兩種途徑來通過GCD“榨取”多核心系統(tǒng)的性能:將單一任務(wù)或者一組相關(guān)任務(wù)并發(fā)至全局隊列中運算;將多個不相關(guān)的任務(wù)或者關(guān)聯(lián)不緊密的任務(wù)并發(fā)至用戶隊列中運算;
設(shè)想下面的循環(huán): ? ? for(id obj in array){? [self doSomethingIntensiveWith:obj]; ? ? }? 假定 -doSomethingIntensiveWith: 是線程安全的且可以同時執(zhí)行多個.一個array通常包含多個元素,這樣的話,我們可以很簡單地使用GCD來平行運算: ? ? ? ? dispatch_queue_t queue = ? ?dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); ? ? for(id obj in array){ ? ? ? ? dispatch_async(queue, ^{ ? ? ? ? ? ? [self doSomethingIntensiveWith:obj]; ? ? ? ? }); ? ? } 如此簡單,我們已經(jīng)在多核心上運行這段代碼了。?
當(dāng)然這段代碼并不完美。有時候我們有一段代碼要像這樣操作一個數(shù)組,但是在操作完成后,我們還需要對操作結(jié)果進(jìn)行其他操作: ? ? for(id obj in array){ ? ? ? ? [self doSomethingIntensiveWith:obj]; ? ? } ? ? [self doSomethingWith:array]; 這時候使用GCD的 dispatch_async 就悲劇了.我們還不能簡單地使用dispatch_sync來解決這個問題, 因為這將導(dǎo)致每個迭代器阻塞,就完全破壞了平行計算。
解決這個問題的一種方法是使用dispatch group。一個dispatch group可以用來將多個block組成一組以監(jiān)測這些Block全部完成或者等待全部完成時發(fā)出的消息。使用函數(shù)dispatch_group_create來創(chuàng)建,然后使用函數(shù)dispatch_group_async來將block提交至一個dispatch queue,同時將它們添加至一個組。 所以我們現(xiàn)在可以重新代碼: ? ? dispatch_queue_t queue = dispatch_get_global_qeueue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); ? ? dispatch_group_t group = dispatch_group_create(); ? ? for(id obj in array) ? ? ? ? dispatch_group_async(group, queue, ^{ ? ? ? ? ? ? [self doSomethingIntensiveWith:obj]; ? ? ? ? }); ? ? dispatch_group_wait(group, DISPATCH_TIME_FOREVER); ? ? dispatch_release(group); ? ? [self doSomethingWith:array];
如果這些工作可以異步執(zhí)行,那么我們可以更風(fēng)騷一點,將函數(shù)-doSomethingWith:放在后臺執(zhí)行。我們使用dispatch_group_async函數(shù)建立一個block在組完成后執(zhí)行: ? ? dispatch_queue_t queue = dispatch_get_global_qeueue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); ? ? dispatch_group_t group = dispatch_group_create(); ? ? for(id obj in array) ? ? ? ? dispatch_group_async(group, queue, ^{ ? ? ? ? ? ? [self doSomethingIntensiveWith:obj]; ? ? ? ? }); ? ? dispatch_group_notify(group, queue, ^{ ? ? ? ? [self doSomethingWith:array]; ? ? }); ? ? dispatch_release(group); 不僅所有數(shù)組元素都會被平行操作,后續(xù)的操作也會異步執(zhí)行,并且這些異步運算都會將程序的其他部分考慮在內(nèi)。注意如果-doSomethingWith:需要在主線程中執(zhí)行,比如操作GUI,那么我們只要將main queue而非全局隊列傳給dispatch_group_notify函數(shù)就行了。
對于同步執(zhí)行,GCD提供了一個簡化方法叫做dispatch_apply。這個函數(shù)調(diào)用單一block多次,并平行運算,然后等待所有運算結(jié)束,就像我們想要的那樣: ? ? dispatch_queue_t queue = dispatch_get_global_qeueue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); ? ? dispatch_apply([array count], queue, ^(size_t index){ ? ? ? ? [self doSomethingIntensiveWith:[array objectAtIndex:index]]; ? ? }); ? ? [self doSomethingWith:array]; 這很棒,但是異步咋辦?dispatch_apply函數(shù)可是沒有異步版本的。但是我們使用的可是一個為異步而生的API啊!所以我們只要用dispatch_async函數(shù)將所有代碼推到后臺就行了: ? ? dispatch_queue_t queue = dispatch_get_global_qeueue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); ? ? dispatch_async(queue, ^{ ? ? ? ? dispatch_apply([array count], queue, ^(size_t index){ ? ? ? ? ? ? [self doSomethingIntensiveWith:[array objectAtIndex:index]]; ? ? ? ? }); ? ? ? ? [self doSomethingWith:array]; ? ? }); 簡單的要死! 這種方法的關(guān)鍵在于確定我們的代碼是在一次對不同的數(shù)據(jù)片段進(jìn)行相似的操作。如果你確定你的任務(wù)是線程安全的(不在本篇討論范圍內(nèi))那么你可以使用GCD來重寫你的循環(huán)了,更平行更風(fēng)騷。
要看到性能提升,你還得進(jìn)行一大堆工作。比之線程,GCD是輕量和低負(fù)載的,但是將block提交至queue還是很消耗資源的——block需要被拷貝和入隊,同時適當(dāng)?shù)墓ぷ骶€程需要被通知。不要將一張圖片的每個像素作為一個block提交至隊列,GCD的優(yōu)點就半途夭折了。如果你不確定,那么請進(jìn)行試驗。將程序平行計算化是一種優(yōu)化措施,在修改代碼之前你必須再三思索,確定修改是有益的(還有確保你修改了正確的地方)。
二、Subsystem并發(fā)運算 前面的章節(jié)我們討論了在程序的單個subsystem中發(fā)揮多核心的優(yōu)勢。下來我們要跨越多個子系統(tǒng)。 例如,設(shè)想一個程序要打開一個包含meta信息的文檔。文檔數(shù)據(jù)本身需要解析并轉(zhuǎn)換至模型對象來顯示,meta信息也需要解析和轉(zhuǎn)換。但是,文檔數(shù)據(jù)和meta信息不需要交互。我們可以為文檔和meta各創(chuàng)建一個dispatch queue,然后并發(fā)執(zhí)行。文檔和meta的解析代碼都會各自串行執(zhí)行,從而不用考慮線程安全(只要沒有文檔和meta之間共享的數(shù)據(jù)),但是它們還是并發(fā)執(zhí)行的。
一旦文檔打開了,程序需要響應(yīng)用戶操作。例如,可能需要進(jìn)行拼寫檢查、代碼高亮、字?jǐn)?shù)統(tǒng)計、自動保存或者其他什么。如果每個任務(wù)都被實現(xiàn)為在不同的dispatch queue中執(zhí)行,那么這些任務(wù)會并發(fā)執(zhí)行,并各自將其他任務(wù)的運算考慮在內(nèi)(respect to each other),從而省去了多線程編程的麻煩。
使用dispatch source(下次我會講到),我們可以讓GCD將事件直接傳遞給用戶隊列。例如,程序中監(jiān)視socket連接的代碼可以被置于它自己的dispatch queue中,這樣它會異步執(zhí)行,并且執(zhí)行時會將程序其他部分的運算考慮在內(nèi)。另外,如果使用用戶隊列的話,這個模塊會串行執(zhí)行,簡化程序。
三、結(jié)論 我們討論了如何使用GCD來提升程序性能以及發(fā)揮多核系統(tǒng)的優(yōu)勢。盡管我們需要比較謹(jǐn)慎地編寫并發(fā)程序,GCD還是使得我們能更簡單地發(fā)揮系統(tǒng)的可用計算資源。
轉(zhuǎn)載自:http://www.dreamingwish.com/dream-2012/of-of-of-performance-of-of-of-of-of-of-of-gcd-introduced-ba-the-multi-core.html
為了在單一進(jìn)程中充分發(fā)揮多核的優(yōu)勢,我們有必要使用多線程技術(shù)。在低層,GCD全局dispatch queue僅僅是工作線程池的抽象。這些隊列中的Block一旦可用,就會被dispatch到工作線程中。提交至用戶隊列的Block最終也會通過全局隊列進(jìn)入相同的工作線程池(除非你的用戶隊列的目標(biāo)是主線程,但是為了提高運行速度,我們絕不會這么干)。
有兩種途徑來通過GCD“榨取”多核心系統(tǒng)的性能:將單一任務(wù)或者一組相關(guān)任務(wù)并發(fā)至全局隊列中運算;將多個不相關(guān)的任務(wù)或者關(guān)聯(lián)不緊密的任務(wù)并發(fā)至用戶隊列中運算;
設(shè)想下面的循環(huán): ? ? for(id obj in array){? [self doSomethingIntensiveWith:obj]; ? ? }? 假定 -doSomethingIntensiveWith: 是線程安全的且可以同時執(zhí)行多個.一個array通常包含多個元素,這樣的話,我們可以很簡單地使用GCD來平行運算: ? ? ? ? dispatch_queue_t queue = ? ?dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); ? ? for(id obj in array){ ? ? ? ? dispatch_async(queue, ^{ ? ? ? ? ? ? [self doSomethingIntensiveWith:obj]; ? ? ? ? }); ? ? } 如此簡單,我們已經(jīng)在多核心上運行這段代碼了。?
當(dāng)然這段代碼并不完美。有時候我們有一段代碼要像這樣操作一個數(shù)組,但是在操作完成后,我們還需要對操作結(jié)果進(jìn)行其他操作: ? ? for(id obj in array){ ? ? ? ? [self doSomethingIntensiveWith:obj]; ? ? } ? ? [self doSomethingWith:array]; 這時候使用GCD的 dispatch_async 就悲劇了.我們還不能簡單地使用dispatch_sync來解決這個問題, 因為這將導(dǎo)致每個迭代器阻塞,就完全破壞了平行計算。
解決這個問題的一種方法是使用dispatch group。一個dispatch group可以用來將多個block組成一組以監(jiān)測這些Block全部完成或者等待全部完成時發(fā)出的消息。使用函數(shù)dispatch_group_create來創(chuàng)建,然后使用函數(shù)dispatch_group_async來將block提交至一個dispatch queue,同時將它們添加至一個組。 所以我們現(xiàn)在可以重新代碼: ? ? dispatch_queue_t queue = dispatch_get_global_qeueue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); ? ? dispatch_group_t group = dispatch_group_create(); ? ? for(id obj in array) ? ? ? ? dispatch_group_async(group, queue, ^{ ? ? ? ? ? ? [self doSomethingIntensiveWith:obj]; ? ? ? ? }); ? ? dispatch_group_wait(group, DISPATCH_TIME_FOREVER); ? ? dispatch_release(group); ? ? [self doSomethingWith:array];
如果這些工作可以異步執(zhí)行,那么我們可以更風(fēng)騷一點,將函數(shù)-doSomethingWith:放在后臺執(zhí)行。我們使用dispatch_group_async函數(shù)建立一個block在組完成后執(zhí)行: ? ? dispatch_queue_t queue = dispatch_get_global_qeueue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); ? ? dispatch_group_t group = dispatch_group_create(); ? ? for(id obj in array) ? ? ? ? dispatch_group_async(group, queue, ^{ ? ? ? ? ? ? [self doSomethingIntensiveWith:obj]; ? ? ? ? }); ? ? dispatch_group_notify(group, queue, ^{ ? ? ? ? [self doSomethingWith:array]; ? ? }); ? ? dispatch_release(group); 不僅所有數(shù)組元素都會被平行操作,后續(xù)的操作也會異步執(zhí)行,并且這些異步運算都會將程序的其他部分考慮在內(nèi)。注意如果-doSomethingWith:需要在主線程中執(zhí)行,比如操作GUI,那么我們只要將main queue而非全局隊列傳給dispatch_group_notify函數(shù)就行了。
對于同步執(zhí)行,GCD提供了一個簡化方法叫做dispatch_apply。這個函數(shù)調(diào)用單一block多次,并平行運算,然后等待所有運算結(jié)束,就像我們想要的那樣: ? ? dispatch_queue_t queue = dispatch_get_global_qeueue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); ? ? dispatch_apply([array count], queue, ^(size_t index){ ? ? ? ? [self doSomethingIntensiveWith:[array objectAtIndex:index]]; ? ? }); ? ? [self doSomethingWith:array]; 這很棒,但是異步咋辦?dispatch_apply函數(shù)可是沒有異步版本的。但是我們使用的可是一個為異步而生的API啊!所以我們只要用dispatch_async函數(shù)將所有代碼推到后臺就行了: ? ? dispatch_queue_t queue = dispatch_get_global_qeueue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); ? ? dispatch_async(queue, ^{ ? ? ? ? dispatch_apply([array count], queue, ^(size_t index){ ? ? ? ? ? ? [self doSomethingIntensiveWith:[array objectAtIndex:index]]; ? ? ? ? }); ? ? ? ? [self doSomethingWith:array]; ? ? }); 簡單的要死! 這種方法的關(guān)鍵在于確定我們的代碼是在一次對不同的數(shù)據(jù)片段進(jìn)行相似的操作。如果你確定你的任務(wù)是線程安全的(不在本篇討論范圍內(nèi))那么你可以使用GCD來重寫你的循環(huán)了,更平行更風(fēng)騷。
要看到性能提升,你還得進(jìn)行一大堆工作。比之線程,GCD是輕量和低負(fù)載的,但是將block提交至queue還是很消耗資源的——block需要被拷貝和入隊,同時適當(dāng)?shù)墓ぷ骶€程需要被通知。不要將一張圖片的每個像素作為一個block提交至隊列,GCD的優(yōu)點就半途夭折了。如果你不確定,那么請進(jìn)行試驗。將程序平行計算化是一種優(yōu)化措施,在修改代碼之前你必須再三思索,確定修改是有益的(還有確保你修改了正確的地方)。
二、Subsystem并發(fā)運算 前面的章節(jié)我們討論了在程序的單個subsystem中發(fā)揮多核心的優(yōu)勢。下來我們要跨越多個子系統(tǒng)。 例如,設(shè)想一個程序要打開一個包含meta信息的文檔。文檔數(shù)據(jù)本身需要解析并轉(zhuǎn)換至模型對象來顯示,meta信息也需要解析和轉(zhuǎn)換。但是,文檔數(shù)據(jù)和meta信息不需要交互。我們可以為文檔和meta各創(chuàng)建一個dispatch queue,然后并發(fā)執(zhí)行。文檔和meta的解析代碼都會各自串行執(zhí)行,從而不用考慮線程安全(只要沒有文檔和meta之間共享的數(shù)據(jù)),但是它們還是并發(fā)執(zhí)行的。
一旦文檔打開了,程序需要響應(yīng)用戶操作。例如,可能需要進(jìn)行拼寫檢查、代碼高亮、字?jǐn)?shù)統(tǒng)計、自動保存或者其他什么。如果每個任務(wù)都被實現(xiàn)為在不同的dispatch queue中執(zhí)行,那么這些任務(wù)會并發(fā)執(zhí)行,并各自將其他任務(wù)的運算考慮在內(nèi)(respect to each other),從而省去了多線程編程的麻煩。
使用dispatch source(下次我會講到),我們可以讓GCD將事件直接傳遞給用戶隊列。例如,程序中監(jiān)視socket連接的代碼可以被置于它自己的dispatch queue中,這樣它會異步執(zhí)行,并且執(zhí)行時會將程序其他部分的運算考慮在內(nèi)。另外,如果使用用戶隊列的話,這個模塊會串行執(zhí)行,簡化程序。
三、結(jié)論 我們討論了如何使用GCD來提升程序性能以及發(fā)揮多核系統(tǒng)的優(yōu)勢。盡管我們需要比較謹(jǐn)慎地編寫并發(fā)程序,GCD還是使得我們能更簡單地發(fā)揮系統(tǒng)的可用計算資源。
轉(zhuǎn)載自:http://www.dreamingwish.com/dream-2012/of-of-of-performance-of-of-of-of-of-of-of-gcd-introduced-ba-the-multi-core.html
總結(jié)
以上是生活随笔為你收集整理的GCD简介二:多核心的性能的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: @interface使用详解
- 下一篇: linux---基础02