GCD多線程的使用


轉載自http://blog.csdn.net/nono_love_lilith/article/details/7829557

寫得非常好

 1.下面來看下如何使用gcd編程的異步

 

[cpp]  view plain copy
 
  1. dispatch_async(dispatch_get_global_queue(0, 0), ^{  
  2.     // 處理耗時操作的代碼塊...  
  3.       
  4.     //通知主線程刷新  
  5.     dispatch_async(dispatch_get_main_queue(), ^{  
  6.         //回調或者說是通知主線程刷新,  
  7.     });  
  8.       
  9. });  


dispatch_async開啟一個異步操作,第一個參數是指定一個gcd隊列,第二個參數是分配一個處理事物的程序塊到該隊列。

 

dispatch_get_global_queue(0, 0),指用了全局隊列。

一般來說系統本身會有3個隊列。

global_queue,current_queue,以及main_queue.

獲取一個全局隊列是接受兩個參數,第一個是我分配的事物處理程序塊隊列優先級。分高低和默認,0為默認2為高,-2為低

 

[cpp]  view plain copy
 
  1. #define DISPATCH_QUEUE_PRIORITY_HIGH     2  
  2. #define DISPATCH_QUEUE_PRIORITY_DEFAULT  0  
  3. #define DISPATCH_QUEUE_PRIORITY_LOW     (-2)  

處理完事物后,需要將結果返回給或者是刷新UI主線程,同樣,和上面一樣,抓取主線程,程序塊操作。

 

//天啊,手賤不小心點到了home間,會退后發現沒保存~~~寫的並發一塊內容都沒了!!!

 

二:GCD之並發概念

其實對於編程中,我們一直提及到的幾個概念,同步,異步,並發,鎖等。

有時覺得一下子還真說不清。

 

下面我們以上面提到的圖片加載來看下這3個概念我的理解

1同步:

 

[cpp]  view plain copy
 
  1. for (int i = 0 ; i < 10; i++) {  
  2.      
  3.       UIImage *img = [self getImgeWith:[urlArr objectForIndex:i]];  
  4.        [myImgV[i] setImage:img];  
  5.        
  6.  }  


假設我要加載10個圖片,我現在擁有這些圖片的資源地址,保存在一個數組中。

 

我們先以獲取第一張圖片來舉例:

同步執行的概念就是,我獲取完第一張圖片的,

執行了for循環第一句返回了img后,我才能執行第二句,UI界面的刷新。

如果第一句返回的時間需要10秒,那我程序的響應就仿佛一直卡在這里一樣,我無法進行其他操作。必須等它返回!!

因此,同步的一個很好理解的感念就是,一步走到黑。

2.異步

 

[cpp]  view plain copy
 
  1. for (int i = 0 ; i < 10; i++) {  
  2.       dispatch_async(dispatch_get_global_queue(0, 0), ^{  
  3.       // 處理耗時操作的代碼塊...  
  4.        UIImage *img = [self getImgeWith:[urlArr objectForIndex:i]];  
  5.       //通知主線程刷新  
  6.       dispatch_async(dispatch_get_main_queue(), ^{  
  7.           //回調或者說是通知主線程刷新,  
  8.             [myImgV[i] setImage:img];  
  9.       });  
  10.         
  11.   });  


看了這代碼,我們會說,異步操作那個假設還是要10秒啊,總體看來,執行一張圖片的時間加載還是要在10秒左右啊,

 

貌似異步沒什么鳥用么。但是,別忽略了其中一點,也黑絲核心的一點,此時我們圖片獲取操作放在里一個線程隊列里,

此刻,雖然我們看着圖片的加載還是需要10秒才會出來,但是,在這10秒期間,我們的UI主線程是可以操作的,比如界面上有個按鈕,你是可以按的

而不是如上面的同步,在10面期間,我是只能干等着,什么都做不了。

異步的核心概念就是一個新線程,一個消息回調通知。

3.並行

我們還是以上代碼為例。前面我強調了,我們只看一張圖片的加載,現在,回到我們第一眼看到代碼的思維上去,

一個for循環。其實上面代碼過后,我是創建了10個異步線程。

好吧,到此,我們應該明白這三個概念了。

同步,其實我前面的例子舉得有些局限,就是這個例子本身就說明不需要同步執行,然后給大家大感覺是

同步是編程中一個忌諱點一樣,其實不然,很多時候。我們真是需要同步來做一些限制(比如線程中提出的同步鎖?聽着就感覺有用么

雖然可能並不如我們想的那樣的運用同步,但是至少說明這個概念同樣是有用的)

我還是以剛才那個加載圖片為例子,來個簡單的說明如何運用同步的好處。

當然,我只是模擬一個同步的情況。

假設我們現在圖片的加載是這樣的,圖片本身為在加載前是一個默認的圖片,上面寫着,點擊我加載,點擊后會調用網絡加載方法,然后圖片顯示加載中,

然后我們雙擊圖片時(當然,理論上是在加載完后)讀取圖片網絡圖片放大,好吧,到這里應該能想到要表達的情況了。

整個流程應該是點擊圖片->加載->雙擊查看。那如果成了點擊->加載中(以返回了圖片的作者和信息)-》雙擊圖片(通過前面請求返回的大圖鏈接顯示大圖)-》

完全加載返回(返回了大圖鏈接)。此時我們看不到圖像的大圖了。因為我們操作在返回前了,也就是說,

很多時候,我們下一個動作的操作必須需要用到前面一個操作的數據時,我們會給他做認為的同步編程,比如加個按鈕鎖。

這是我們又會疑惑道,下一個執行需要用到前一個執行的,那第一個例子中的for循環的第二句不是要用到么,這么說

他們必須要同步啊,如果你這么想了,好巧,我們想到一塊去了~

但是,注意,前面我們到的異步是為了解決我點擊其他按鈕的操作,而不是說更新UI操作。下載和更新UI操作在我們看來必須是同步的

這是對的,但是那種做導致了系統本身一些監聽事件監聽到點擊處理在那個請求之后了,這邊的加載圖片其實要看成一次事件執行,

因為對於事件的這一抽象單元,其實是一種可人為定義的寬廣度。

也就是說,一次數據獲取和圖像填充,其實算是一個圖像獲取加載事件,事件可以說包含兩個單元,加載和填充。

而整個這個事件對於我們點擊其他按鈕並無關系,那么也就說明了無需同步。

有道理啊,但是若果我們要點擊這個圖片呢,也就是回到剛才那個可以雙擊的假設。

此處也許我么又忽略了一點為什么加載中我們能點擊雙擊呢,也就這樣的假設是獲取圖片已經做了異步,但是我們下一步操作又是需要同步的

因此做了人為的同步鎖定。

好了,說的太多了,當時至少我們明白兩點

異步可能是為了反正耗時操作造成的主線程堵塞,

同步是為了解決一些不必要錯誤和麻煩。也許到這里,我們腦中會聯想到的所謂的線程安全性。

其實同步以及同步鎖,卻是應該是考慮到這樣的不必要和不安全因素。

 

最后在簡單闡述下異步和並發關系。

其實看了上面說的,異步只是提供了一種多線程處理的概念,

並發是更像是異步的一種大規模實現。

就好比說,異步提出了可以用小弟去收保護費,收完了告訴並交給自己,而我在期間做其他要做的事。

並發突然想到,異步這個很有道理啊,那我有4個地方要收,一個小弟去收,雖然我還是可以閑着做其他的事,

但是小弟跑四個地方,我拿到錢所需要的時間還是和我自己去收一樣的,只不過我不用那么費勁了,還能做其他事了。

因此,並發覺得應該派四個小弟去,因為每個場地的保護費各不相干的。(剛看了個紐約黑幫~)。

 

因此說,異步解決了線程堵塞,而並發則是在異步的基礎上,提高了符合特性事件的處理時間效率。

 

當然,如果10個圖片本身相互間是沒什么聯系,但是,最后一個事件需要處理計算這10個圖片的總容量值。

那么可以用 dispatch_group_async。

具體就看文檔吧。

 

總體來說,看了iosGCD這塊,一是讓我熟悉了block編程特性,還有是熟悉如何使用ios提供的GCD特性

來完成多線程編程。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM