15

在Apple的「併發編程指南」的「從線程遷移」部分中,有
Changing Producer-Consumer Implementations,它聲稱使用GCD可以簡化典型的multistep pthread mutex +條件變量實現。蘋果公司的GCD生產者 - 消費者解決方案是否錯誤?

隨着調度隊列,可以簡化生產者和消費者 實現成一個單一的電話:

dispatch_async(queue, ^{ 
    // Process a work item. 
}); 

當你的生產者必須要做的工作,所有它做的是將該工作添加到隊列並讓隊列處理該項目。

生產者 - 消費者問題也被稱爲有界緩衝區的問題,但在上述沒有提到的緩衝液中,其結合或消費者,更不用說以避免過度阻塞生產者&消費者/在運行。

這怎麼可能是一個有效的解決方案?

+0

但是在這種情況下,從性能命中的角度來看,有兩個線程同時運行生產者和消費者,在系統初始化期間啓動,或者在生產者有更多數據添加時調度異步線程(因爲調度一個線程也需要它自己的甜蜜時間)。 – Ichthyocentaurs

+0

隊列是緩衝區。 –

回答

22

在上述方案中描述下,在蘋果的文檔:

  1. 沒有緩衝區,因爲不需要緩衝;
  2. 系統負載是綁定的;
  3. 消費者是任務。

假設您有多個生產者和消費者,生產者將數據放入共享緩衝區,消費者從該共享緩衝區讀取數據。信號量或監視器用於同步對共享緩衝區的訪問,並且緩衝區大小是固定的,以便根據正在消耗的速率限制正在生成的數據量,從而限制生產者。

在Grand Central Dispatch下,消費者是派發到隊列的任務。由於任務是Objective-C塊,因此生產者不需要緩衝區來告知消費者應該處理的數據:Objective-C塊會自動捕獲它們引用的對象。

例如:

// Producer implementation 
while (…) { 
    id dataProducedByTheProducer; 

    // Produce data and place it in dataProducedByTheProducer 
    dataProducedByTheProducer = …; 

    // Dispatch a new consumer task 
    dispatch_async(queue, ^{ 
     // This task, which is an Objective-C block, is a consumer. 
     // 
     // Do something with dataProducedByTheProducer, which is 
     // the data that would otherwise be placed in the shared 
     // buffer of a traditional, semaphore-based producer-consumer 
     // implementation. 
     // 
     // Note that an Objective-C block automatically keeps a 
     // strong reference to any Objective-C object referenced 
     // inside of it, and the block releases said object when 
     // the block itself is released. 

     NSString *s = [dataProducedByTheProducer …]; 
    }); 
} 

生產者可以將盡可能多的消費者的任務,它可以產生數據。但是,這並不意味着GCD將以相同的速度觸發消費者任務。 GCD使用操作系統信息來控制根據當前系統負載執行的任務數量。生產者本身並沒有被限制,在大多數情況下,它不一定是因爲GCD的內在負載平衡。

如果實際需要扼制生產者,一種解決方案是讓主人調度生產者任務並讓每個消費者通知主人(通過在消費者完成其工作之後調度的任務)它已經結束,在這種情況下,主人會派遣另一個生產者任務。或者,消費者本身可以在完成後派遣生產者任務。

具體回答您已經解決的項目:

生產者 - 消費者問題也被稱爲有界緩衝區的問題,但上面沒有提到的緩衝

A的共享緩衝區是不需要的,因爲消費者是Objective-C塊,它會自動捕獲它們引用的數據。

其綁定

GCD界定根據當前系統負載的分派任務數目。

或消費者

消費者派往GCD隊列的任務。

更不用說爲了阻止生產者&消費者避免過/下運行

沒有必要阻止,因爲沒有共享緩存。由於每個消費者都是通過Objective-C塊上下文捕獲機制捕獲生成數據的Objective-C塊,因此消費者和數據之間存在一對一的關係。

+1

哇,這太好了。我必須考慮這一點。謝謝! –

+2

好吧,我現在明白了。這是齒輪的精神變化,簡化了事情。我對這個不透明的隊列有點擔心,儘管我看到我可以做到幾乎所有我可以做到的事情,除了可能拿下未完成的消費者任務。我會在新的代碼中使用它,但對於我想到的問題,我不能像我的消費者安排在真正的線程中那樣。謝謝你的出色答案,太糟糕了,你不是在寫doco。 –

+0

我不喜歡這個解決方案的是生產者決定消費者如何消費數據(它必須指定塊)。而我可能希望消費者能夠從代碼中的各個位置使用數據,具體取決於它處理的步驟。 – user102008