2012-06-08 171 views
14

是否可以通過將maxConcurrentOperationCount設置爲1來將NSoperationQueue對象用作串行FIFO隊列?NSOperationQueue串行FIFO隊列

我注意到docs狀態...

對於隊列,其併發操作的最大數量設置爲1,這相當於一個串行隊列。但是,不應該依賴於操作對象的串行執行。

這是否意味着FIFO執行不能保證?

回答

23

在大多數情況下,它將是FIFO。但是,您可以設置NSOperations之間的依賴關係,以便提前提交的操作可以讓其他操作在隊列中傳遞它,直到它的依賴性得到滿足。

這種依賴性管理是文檔顯示無法保證FIFO性能的原因。不過,如果你不使用依賴關係,那麼依靠它應該沒問題。

更新: 的NSOperation也有queuePriority屬性,它也可能導致操作在非FIFO的順序執行。沒有掛起依賴關係的最高優先級操作將始終首先執行。

NSOperation子類也可能會覆蓋-isReady,這可能會導致它回到隊列中。

因此,您的隊列上的執行保證爲serial,因爲此隊列中一次只能運行一個操作。但是,蘋果不能保證FIFO;這取決於你和你把作業做什麼

+0

執行順序還取決於操作的隊列優先級。 – JeremyP

+0

非常真實。更新。 –

+0

因此,如果我的操作都具有相同的優先級,沒有依賴關係,並且只依賴'isReady'的超類實現(我不覆蓋),它應該導致一個FIFO隊列? – Barjavel

-2

要使用nsInvocationopration 做一個簡單的FIFO,您將需要設置一個操作上的其他 要依靠使用addDependency:方法

NSOperationQueue *queue = [[NSOperationQueue alloc] init]; 
NSInvocationOperation *oper1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(doSth:) object:@"1"]; 

NSInvocationOperation *oper2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(doSth:) object:@"2"]; 
NSInvocationOperation *oper3 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(doSth:) object:@"3"]; 

[oper2 addDependency:oper1]; 
[oper3 addDependency:oper2]; 
//oper3 depends on oper2 wich depends on oper1 
//order of execution will ber oper1->oper2->oper3 

//Changing the oreder will not change the result 
[queue addOperation:oper2]; 
[queue addOperation:oper3]; 
[queue addOperation:oper1]; 


- (void) doSth:(NSString*)str 
{ 
    NSLog(str); //log will be 1 2 3 
    //When you remove the addDependency calls, the logging result that i got where 
    //different between consecutive runs i got the following 
    //NSLog(str); //log will be 2 1 3 
    //NSLog(str); //log will be 3 1 2 
} 

注意:如果您使用的NSInvocationOperation然後設置maxConcurrentOperationCount 1將最有可能做的伎倆給你,因爲的isReady將不會對你

但編輯= 1就不會是一個很好的解決方案,如果你是刨去創建自己的NSOperation

子自的NSOperation衍生工具,你可以重寫isReady功能和返回無,(想象一下一些操作,將需要等待一些數據一臺服務器,以便在這些情況下正常工作),你將返回isReady no,直到你真的準備好 在這些情況下,您將需要operations之間添加dependencies隊列

內從蘋果公司的文檔這相當於一個串行隊列。但是,你不應該依賴於操作對象的串行執行。在操作的準備就緒的變化可改變所得執行順序

+0

你能解釋爲什麼依賴是必要的嗎? –

+0

@BJHomer我已更新我的答案,包括一些日誌記錄 –

+0

您的隊列在示例中沒有像指定的OP那樣的'maxConcurrentOperationCount = 1'。這套裝置是否仍然會發生? –

12

由文檔中提到的隊列沒有FIFO。如果您確保任何新操作取決於隊列中添加的最後一個操作,並且它一次只能運行一個操作,則可以將其嚴格設置爲FIFO。奧馬爾的解決方案是正確的,但更普遍的,你可以做到以下幾點:

NSOperationQueue* queue = [[ NSOperationQueue alloc ] init]; 
queue.maxConcurrentOperationCount = 1; 

NSOperation* someOperation = [ NSBlockOperation blockOperationWithBlock:^(void) { NSLog(@"Done.");} ]; 

if (queue.operations.count != 0) 
    [ someOperation addDependency: queue.operations.lastObject ]; 

這工作,因爲queue.operations是一個數組:無論你加不重新排序(它不是實例的NSSet)。你也可以簡單的類別添加到您的NSOperationQueue:

@interface NSOperationQueue (FIFOQueue) 
- (void) addOperationAfterLast:(NSOperation *)op; 
@end 

@implementation NSOperationQueue (FIFOQueue) 

- (void) addOperationAfterLast:(NSOperation *)op 
{ 
    if (self.maxConcurrentOperationCount != 1) 
     self.maxConcurrentOperationCount = 1; 

    NSOperation* lastOp = self.operations.lastObject; 
    if (lastOp != nil) 
     [ op addDependency: lastOp ]; 

    [ self addOperation:op]; 
} 

@end 

,並使用[隊列addOperationAfterLast:myOperation。 queuePriority與FIFO無關,它與作業調度有關。

編輯:在下面的評論之後,如果檢查計數,暫停隊列也是不夠的。我相信這種形式是好的(經過測試,這不會造成競爭狀況,也不會崩潰)。

某些信息:https://developer.apple.com/library/mac/documentation/Cocoa/Reference/NSOperationQueue_class/#//apple_ref/occ/instp/NSOperationQueue/suspended

+0

這種類型的解決方案存在問題。我一直在使用它。偶爾,隊列的lastObject將在檢查queue.operations.count後消失。這很少見,但它發生了。我不確定如何解決它。 –

+0

好點我沒有看到,但是:如果在隊列運行時檢查operations.count,它可能會在我們輸入if條件時結束。我相信編輯後的表格更好更安全:(這裏的測試不會崩潰,而嘗試暫停隊列的測試不起作用(未顯示))。 – Daniel

+0

這也是我也參與的解決方案;創建一個局部變量,防止NSOperation被釋放。 –