我正在研究框架并且为了确保非阻塞公共方法,我使用NSOperationQueue
将所有公共方法调用放入操作队列并立即返回。
不同操作之间没有关系或依赖关系,唯一重要的是操作以FIFO顺序启动,其顺序与添加到队列的顺序相同。
以下是我当前实施的示例(sample project here):
@implementation Executor
-(instancetype) init {
self = [super init];
if(self) {
_taskQueue = [[NSOperationQueue alloc] init];
_taskQueue.name = @"com.d360.tasks";
}
return self;
}
-(void) doTask:(NSString*) taskName
{
NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"executing %@", taskName);
}];
[self.taskQueue addOperation:operation];
}
我意识到操作的启动顺序不一定是它们添加到队列的顺序。例如,如果我打电话
[self.executor doTask:@"Task 1"];
[self.executor doTask:@"Task 2"];
有时候Task 2
会在Task 1
之后启动。
问题是如何确保FIFO执行开始?
我可以使用_taskQueue.maxConcurrentOperationCount = 1;
来实现它,但这只允许我一次只能操作一次,我不想要。一个操作不应该阻止任何其他操作,只要它们以正确的顺序启动它们就可以并发运行。
我还查看了NSOperationQueuePriority
属性,如果我知道电话的优先级,我就不会这样做。实际上,即使我将先前添加的操作发送到NSOperationQueuePriorityHigh
而第二个添加到NSOperationQueuePriorityNormal
,也不保证订单。
[self.executor doTask:@"Task 1" withQueuePriority:NSOperationQueuePriorityHigh];
[self.executor doTask:@"Task 2" withQueuePriority:NSOperationQueuePriorityNormal];
输出有时是
executing Task 2
executing Task 1
有什么想法吗?
感谢, 扬
答案 0 :(得分:1)
创建每个任务时,您可以使用NSOperation -addDependency
添加对上一个任务的依赖关系。复杂的是在依赖任务完成之前不满足依赖性,这可能不是你想要的。您可以通过在每个任务中创建另一个NSOperation来解决这个问题,并使下一个排队的任务依赖于那个。这个内部任务可以设置一个标志或者说“嘿,我已经开始!”的东西。然后,当该内部任务完成时,它将满足队列中下一个任务的依赖性并允许它开始。
看起来似乎是一种令人费解的做事方式,而且我不确定这种好处是否值得额外的复杂化 - 为什么操作的起始顺序是重要的,如果它们真的是独立的操作?一旦它们启动,操作系统就决定哪个任务获得CPU时间,并且你无论如何都没有太多的控制权,那么为什么不将它们排队并让操作系统管理启动命令呢?