是否可以通过将maxConcurrentOperationCount
设置为1来将NSoperationQueue
对象用作串行FIFO队列?NSOperationQueue串行FIFO队列
我注意到docs状态...
对于队列,其并发操作的最大数量设置为1,这相当于一个串行队列。但是,不应该依赖于操作对象的串行执行。
这是否意味着FIFO执行不能保证?
是否可以通过将maxConcurrentOperationCount
设置为1来将NSoperationQueue
对象用作串行FIFO队列?NSOperationQueue串行FIFO队列
我注意到docs状态...
对于队列,其并发操作的最大数量设置为1,这相当于一个串行队列。但是,不应该依赖于操作对象的串行执行。
这是否意味着FIFO执行不能保证?
在大多数情况下,它将是FIFO。但是,您可以设置NSOperations之间的依赖关系,以便提前提交的操作可以让其他操作在队列中传递它,直到它的依赖性得到满足。
这种依赖性管理是文档显示无法保证FIFO性能的原因。不过,如果你不使用依赖关系,那么依靠它应该没问题。
更新: 的NSOperation也有queuePriority
属性,它也可能导致操作在非FIFO的顺序执行。没有挂起依赖关系的最高优先级操作将始终首先执行。
NSOperation子类也可能会覆盖-isReady
,这可能会导致它回到队列中。
因此,您的队列上的执行保证为serial,因为此队列中一次只能运行一个操作。但是,苹果不能保证FIFO;这取决于你和你把作业做什么
要使用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
队列
内从苹果公司的文档这相当于一个串行队列。但是,你不应该依赖于操作对象的串行执行。在操作的准备就绪的变化可改变所得执行顺序
你能解释为什么依赖是必要的吗? –
@BJHomer我已更新我的答案,包括一些日志记录 –
您的队列在示例中没有像指定的OP那样的'maxConcurrentOperationCount = 1'。这套装置是否仍然会发生? –
由文档中提到的队列没有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无关,它与作业调度有关。
编辑:在下面的评论之后,如果检查计数,暂停队列也是不够的。我相信这种形式是好的(经过测试,这不会造成竞争状况,也不会崩溃)。
这种类型的解决方案存在问题。我一直在使用它。偶尔,队列的lastObject将在检查queue.operations.count后消失。这很少见,但它发生了。我不确定如何解决它。 –
好点我没有看到,但是:如果在队列运行时检查operations.count,它可能会在我们输入if条件时结束。我相信编辑后的表格更好更安全:(这里的测试不会崩溃,而尝试暂停队列的测试不起作用(未显示))。 – Daniel
这也是我也参与的解决方案;创建一个局部变量,防止NSOperation被释放。 –
执行顺序还取决于操作的队列优先级。 – JeremyP
非常真实。更新。 –
因此,如果我的操作都具有相同的优先级,没有依赖关系,并且只依赖'isReady'的超类实现(我不覆盖),它应该导致一个FIFO队列? – Barjavel