2016-10-21 61 views
2

今天,我已經試過下面的代碼:暫停串行隊列

- (void)suspendTest { 
    dispatch_queue_attr_t attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_CONCURRENT, QOS_CLASS_BACKGROUND, 0); 
    dispatch_queue_t suspendableQueue = dispatch_queue_create("test", attr); 
    for (int i = 0; i <= 10000; i++) { 
     dispatch_async(suspendableQueue, ^{ 
      NSLog(@"%d", i); 
     }); 
     if (i == 5000) { 
      dispatch_suspend(suspendableQueue); 
     } 
    } 
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(6 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 
     NSLog(@"Show must go on!"); 
     dispatch_resume(suspendableQueue); 
    }); 
} 

的代碼開始10001級的任務,但它應該暫停運行新任務隊列爲中途在6秒內恢復。此代碼按預期工作 - 執行5000個任務,然後隊列停止,並在6秒後恢復。 但是,如果我使用串行隊列,而不是併發隊列,行爲不明確。

dispatch_queue_attr_t attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_BACKGROUND, 0); 

在這種情況下任務的隨機數理暫停之前執行,但往往這個數字接近於零(懸浮之前的任何任務發生)。 問題是 - 爲什麼暫停串行和併發隊列的工作以及如何正確暫停串行隊列?

+1

您發佈的代碼不會編譯。你的'if(i == 5000){'行在for循環之後。 – rmaddy

+0

我的錯,我只是通過記憶來重現它。讓我來修復它 –

+2

好的,所以這是其中的一個問題,你不能將你的真實代碼粘貼到瀏覽器中?我無法理解這一點。 – matt

回答

1

按它的名稱,序列隊列系列執行的任務,即前一個已經完成後的下一個纔剛剛開始。優先級是後臺,所以在當前隊列到達第5000個任務並暫停隊列時,它甚至可能不會在第一個任務上啓動。

dispatch_suspend文檔:

將懸浮液在該呼叫的時間運行的任何塊的結束之後發生。

即無處它承諾異步分派隊列的任務將完成,只是任何當前正在運行的任務(塊)將不會被通過懸掛部分的方式。在串行隊列上,最多一個任務可以是「當前正在運行」,而在併發隊列中沒有指定的上限。 編輯:而根據你對百萬個任務的測試,看起來併發隊列維持概念抽象,認爲它是「完全併發」的,因此即使它們實際上沒有,也認爲它們都是「當前正在運行」。

到了5000次任務後暫停它,你可以從第5000個任務本身觸發此。 (那麼你可能也想開始從它被暫停的時間與恢復計時器,否則它在理論上是可能永遠不會恢復,如果恢復發生被掛起之前。)

+0

那麼爲什麼併發隊列像發條一樣運行具有相同的優先級呢? –

+1

@AleksandrMedvedev它並不重要;該API指定了您可以期待的內容,並且您不能指望串行隊列以您想要的方式工作。我的猜測是,因爲它是併發的,它將所有調度的任務視爲「當前正在運行」並讓它們完成,而串行隊列最多隻考慮一個「當前正在運行」的任務。 – Arkku

+0

@AleksandrMedvedev如果您要增加具有併發隊列的任務的數量和長度,這也將是一個有趣的實驗。如果你派遣50,000人並且每個人都做更多工作,它是否仍然有效? – Arkku

1

我認爲問題是,你是混淆suspendbarriersuspend現在停止隊列barrier在屏障執行前的隊列中的所有內容都會停止。因此,如果您在第5000個任務之後放置障礙物,則會在我們暫停串行隊列上的障礙物之前執行5000個任務。

+0

感謝您的建議。我意識到「障礙」,但問題與解決方案無關。我對它是如何工作感興趣的,以及它在暫停和併發隊列方面意味着「已經運行的任務」。無論如何,你的努力表示讚賞。 –