2013-01-18 82 views
4

我正在異步從數據庫中獲取數據。有什麼辦法可以將併發請求限制到一個數字,但仍然執行其餘的?我可以使用GCD限制併發請求嗎?

我看到使用的NSOperation和NSOperationQueue a post但是這對我來說太複雜了。 有沒有其他方法可以做到這一點? GCD可以實現嗎?

+1

我要說的是使用'NSOperation'和'NSOperationQueue'是不是直接使用GCD容易。 'NSOperationQueue'有一個非常方便的'maxConcurrentOperationsCount'屬性。有了GCD,你需要實現你自己的某種計數器。你可以例如使用'dispatch_semaphore'函數家族... – Guillaume

+0

@Guillaume你有我能看到的示例代碼嗎?我讀過一篇教程和課程參考資料,但仍然不太明白。 – user1491987

回答

15

事情是這樣的:

... 
//only make one of these obviously :) remaking it each time you dispatch_async wouldn't limit anything 
dispatch_semaphore_t concurrencyLimitingSemaphore = dispatch_semaphore_create(limit); 
... 
//do this part once per task, for example in a loop 
dispatch_semaphore_wait(concurrencyLimitingSemaphore, DISPATCH_TIME_FOREVER); 
dispatch_async(someConcurrentQueue, ^{ 
    /* work goes here */ 
    dispatch_semaphore_signal(concurrencyLimitingSemaphore); 
} 
+3

欲瞭解更多詳情,請參閱蘋果[併發編程指南(https://developer.apple.com/library/ios/documentation/General/Conceptual/ConcurrencyProgrammingGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40008091 ),特別是部分[使用調度信號量來調節有限資源的使用方法](https://developer.apple.com/library/ios/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html#//apple_ref/ DOC/UID/TP40008091-CH102-SW24)。 –

+1

會不會把'dispatch_semaphore_wait()'調用之前(和外)'dispatch_async()'更好/更高效? – werediver

+0

是的,那麼我們需要把這個循環包裝在'dispatch_async()'中。這樣,我們將在當前運行的頂部_just one_任務,而不是在同一時間所有N. – werediver

-1

最簡單的辦法是設置N個串行隊列

struct dataCalls { 
    let n:Int 
    func fetchIt(){ 
     print ("Done",n) 
    } 

    init(n:Int){ 
     self.n=n 
    } 
} 

var dataCallsArray: [dataCalls]=[] 
var qArray:[dispatch_queue_t] = [] 
let n = 5 
for i in 1...50 { 
    dataCallsArray.append(dataCalls(n:i)) 
} 

for _ in 1...n { 
    qArray.append(dispatch_queue_create(nil, nil)) 
} 

var i = 0 
for data in dataCallsArray { 
    dispatch_async(qArray[i%n], {() -> Void in data.fetchIt()}) 
    i++ 
} 
+0

注意,如果某些隊列比其他隊列落後,這將不會在隊列之間進行負載平衡。 – Ethan

0

我建議這個解決方案的同步任務有限的併發執行:

func dispatch_async_batch(tasks: [() ->()], limit: Int, completion: (() ->())?) { 
    if tasks.count > 0 || completion != nil { 
     let q = dispatch_queue_create("dispatch_async_batch", DISPATCH_QUEUE_CONCURRENT); 
     let sema = dispatch_semaphore_create(limit); 

     dispatch_async(q, { 
      for task in tasks { 
       dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER) 
       dispatch_async(q, { 
        task() 
        dispatch_semaphore_signal(sema) 
       }) 
      } 

      if let completion = completion { 
       dispatch_barrier_async(q, completion) 
      } 
     }) 
    } 
} 

這種方法有小的開銷:只Ø將額外的任務放在隊列中(即一個額外的線程)撇開目前正在執行的。當你有大量的任務時特別好。

gist是準備使用的演示,只是把代碼放到一個遊樂場。

相關問題