2013-02-04 47 views
5

我有一個圖像加載器類提供NSURL負載和圖像從網絡並執行完成塊。代碼其實很簡單問題與GCD和太多的線程

- (void)downloadImageWithURL:(NSString *)URLString completion:(BELoadImageCompletionBlock)completion 
{ 
    dispatch_async(_queue, ^{ 
// dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ 
     UIImage *image = nil; 
     NSURL *URL = [NSURL URLWithString:URLString]; 
     if (URL) { 
      image = [UIImage imageWithData:[NSData dataWithContentsOfURL:URL]]; 
     } 
     dispatch_async(dispatch_get_main_queue(), ^{ 
      completion(image, URLString); 
     }); 
    }); 

}

當我更換

dispatch_async(_queue, ^{ 

與註釋掉

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ 

圖片加載速度更快,至極是很合乎邏輯的(在此之前,圖像將一次加載一個,現在它們中的一羣同時加載)。我的問題是,我可能有50個圖像,我調用downloadImageWithURL:completion:方法,當我使用全局隊列而不是_queue時,我的應用程序最終崩潰,我看到有85個線程。問題是我連續50次調用dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0)會導致GCD創建太多線程?我認爲gcd可以處理所有的線程,並確保線程的數量不是很大,但如果不是這種情況,有什麼辦法可以影響線程的數量?

回答

2
http://developer.apple.com/library/ios/#documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html

併發隊列(也稱爲類

嘛的全局調度隊列)同時執行一個或多個任務,但任務仍以 開始的順序執行編輯隊列。當前執行的任務 在由 調度隊列管理的不同線程上運行。在任何給定的點 執行的任務的確切數量是可變的並且取決於系統條件。

串行隊列(也稱爲專用調度隊列)在它們被添加到隊列中的順序以時間執行一個任務 。當前正在執行的任務的 在由調度隊列管理的不同線程上運行(可以改變從任務到任務的 )。

通過調度所有的塊高優先級的併發調度隊列

[NSData dataWithContentsOfURL:URL] 

這是一個同步阻塞網絡運行,它看起來像默認GCD行爲將生成線程的負載儘快執行你的塊。

您應該派遣到DISPATCH_QUEUE_PRIORITY_BACKGROUND。這些任務絕不是「高優先級」。任何圖像處理都應該在空閒時間完成並且主線程上沒有任何事情發生。

如果您想要更多地控制這些事情發生的時間,我建議您使用NSOperation。你可以把你的區塊嵌入到NSBlockOperation的操作中,然後你可以將這些操作提交給你自己的NSOperationQueue。一個NSOperationQueue有一個- (NSInteger)maxConcurrentOperationCount和作爲一個額外的好處操作也可以在調度後取消,如果需要的話。

+4

不,這與隊列優先級無關.GCD僅在現有線程上爲全局併發隊列在內核中阻塞塊時創建額外的線程,並且花費很少的時間。 – das

+0

@das謝謝我已將一些修改,但請隨時讓我的答案更好:) – jackslash

1

您可以使用NSOperationqueue,這是由NSURLConnection

支持,它具有以下實例方法:

- (void)setMaxConcurrentOperationCount:(NSInteger)count 
8

當全局併發隊列的現有GCD工作線程上的工作單元在內核中被阻塞很長一段時間(只要全局隊列上還有待處理的工作),內核就會創建其他線程。

這是必要的,以便應用程序可以繼續總體上取得進展(例如,其中一個未決塊的執行可能是阻止的線程被解除阻塞)。

如果工作線程在內核中被阻塞的原因是IO(例如在本例中爲+[NSData dataWithContentsOfURL:]),最好的解決方案是用一個將不會異步執行該IO而不阻塞的API替換掉這些調用。 NSURLConnection用於聯網或爲文件系統IO分派I/O。

或者,您可以手動限制併發阻塞操作的數量,例如,通過使用計數調度信號量。

WWDC 2012 GCD會議詳細討論了這個話題。