将 NSoperationQueue
对象的 maxConcurrentOperationCount
属性设置为 1,可以将其作为串行 FIFO 队列使用吗?
我注意到文档中提到...
对于最大并发操作数设置为 1 的队列,这相当于一个串行队列。但是,你不应该依赖操作对象的串行执行。
这是否意味着不能保证 FIFO 执行顺序?
将 NSoperationQueue
对象的 maxConcurrentOperationCount
属性设置为 1,可以将其作为串行 FIFO 队列使用吗?
我注意到文档中提到...
对于最大并发操作数设置为 1 的队列,这相当于一个串行队列。但是,你不应该依赖操作对象的串行执行。
这是否意味着不能保证 FIFO 执行顺序?
根据文档所述,队列不是先进先出的。如果您确保任何新操作都依赖于队列中添加的最后一个操作,并且它一次只能运行单个操作,则可以使其严格遵循FIFO。Omar的解决方案是正确的,但更普遍的做法是:
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
使用queue addOperationAfterLast:myOperation
。队列优先级与FIFO无关,而是与作业调度有关。
编辑:根据下面的评论,如果仅检查数量时挂起队列也是不够的。我认为这种形式是可以的(经过测试,这不会创建竞态条件并且不会崩溃)。
queue.operations.count
检查之后完成。因此问题仍然存在。 - GordoniumNSOperationQueue *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
但是,如果您计划创建自己的NSOperation
子类,则maxConcurrentOperationCount
=1不是一个好的解决方案
因为在NSOperation派生类中,您可以重写isReady
函数并返回no(想象一下某个需要从服务器等待一些数据才能正常运行的操作),在这些情况下,您将返回isReady no
直到您真正准备好了
在这些情况下,您需要在队列内的操作
之间添加依赖关系
来自苹果文档的说明:这相当于串行队列。但是,您永远不应该依赖于操作对象的串行执行。操作的可用性更改可能会更改结果的执行顺序
maxConcurrentOperationCount = 1
。如果设置了这个值,它还会发生吗? - BJ HomerNSInvocationOperation
本身并没有做任何会导致非FIFO执行顺序的事情。 - BJ Homer
isReady
的超类实现(我没有覆盖),那么它应该会产生一个FIFO队列? - Barjavel