这个问题的原因是因为对this question的反应。
我意识到问题的理解并不完全存在,而且首先是问题的原因。所以我试图将其他问题的原因归结为这个问题的原因。
首先是一个小前言和一些历史记录,我知道NSOperation(Queue)在GCD之前就存在了,并且它们是在调度队列之前使用线程实现的。
接下来需要了解的是,默认情况下,意味着没有“等待”方法用于操作或操作队列(只是标准的“addOperation:”),NSOperation的主要内容方法在NSOperationQueue的基础队列上执行异步(例如dispatch_async())。
结束我的序言,我质疑在当天和时代将NSOperationQueue.mainQueue.maxConcurrentOperationCount设置为1的目的,现在底层的Queue实际上是主要的GCD串行队列(例如dispatch_get_main_queue的返回( ))。
如果NSOperationQueue.mainQueue已经连续执行了它的操作主要方法,为什么要担心maxConcurrentOperationCount?
要查看将其设置为1的问题,请参阅引用问题中的示例。
答案 0 :(得分:2)
它被设置为1,因为没有理由将它设置为其他任何东西,并且可能稍微好一点将其设置为1,至少有三个我能想到的原因。
由于NSOperationQueue.mainQueue
的{{1}}是underlyingQueue
,它是串行的,dispatch_get_main_queue()
实际上是串行的(它一次只能运行多个块,甚至如果NSOperationQueue.mainQueue
大于1)。
我们可以通过创建我们自己的maxConcurrentOperationCount
来检查这一点,在其NSOperationQueue
目标链中放置一个串行队列,并将其underlyingQueue
设置为一个大数字。
使用macOS>在Xcode中创建一个新项目; Cocoa App模板,语言为Objective-C。将maxConcurrentOperationCount
实现替换为:
AppDelegate
如果你运行它,你会看到操作1直到操作0结束才开始,即使我将@implementation AppDelegate {
dispatch_queue_t concurrentQueue;
dispatch_queue_t serialQueue;
NSOperationQueue *operationQueue;
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
concurrentQueue = dispatch_queue_create("q", DISPATCH_QUEUE_CONCURRENT);
serialQueue = dispatch_queue_create("q2", nil);
operationQueue = [[NSOperationQueue alloc] init];
// concurrent queue targeting serial queue
//dispatch_set_target_queue(concurrentQueue, serialQueue);
//operationQueue.underlyingQueue = concurrentQueue;
// serial queue targeting concurrent queue
dispatch_set_target_queue(serialQueue, concurrentQueue);
operationQueue.underlyingQueue = serialQueue;
operationQueue.maxConcurrentOperationCount = 100;
for (int i = 0; i < 100; ++i) {
NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"operation %d starting", i);
sleep(3);
NSLog(@"operation %d ending", i);
}];
[operationQueue addOperation:operation];
}
}
@end
设置为100.这是因为目标链中有一个串行队列operationQueue.maxConcurrentOperationCount
。因此,operationQueue.underlyingQueue
实际上是连续的,即使其operationQueue
不是1。
您可以使用代码尝试更改目标链的结构。你会发现,如果该链中的任何地方都有一个串行队列,那么一次只能运行一个操作。
但是如果您设置maxConcurrentOperationCount
,并且不将operationQueue.underlyingQueue = concurrentQueue
的目标设置为concurrentQueue
,那么您将看到64个操作同时运行。要使serialQueue
同时运行操作,以operationQueue
开头的整个目标链必须是并发的。
由于主队列始终是串行的,underlyingQueue
实际上始终是串行的。
实际上,如果将NSOperationQueue.mainQueue
设置为除1以外的任何值,则无效。如果您在尝试更改它之后打印NSOperationQueue.mainQueue.maxConcurrentOperationCount
,您会发现它仍然是1.我认为如果尝试更改它会提出一个断言会更好。默默无视改变它的企图更有可能导致混淆。
NSOperationQueue.mainQueue.maxConcurrentOperationCount
同时向其NSOperationQueue
提交最多maxConcurrentOperationCount
个阻止。由于underlyingQueue
是串行的,因此一次只能运行其中一个块。提交这些块后,使用mainQueue.underlyingQueue
消息取消相应的操作可能为时已晚。我不确定;这是我尚未完全探索的实现细节。无论如何,如果为时已晚,那将是不幸的,因为它可能会浪费时间和电池电量。
正如原因2所述,-[NSOperation cancel]
同时向其NSOperationQueue
提交最多maxConcurrentOperationCount
个阻止。由于underlyingQueue
是串行的,因此一次只能执行其中一个块。其他块以及mainQueue.underlyingQueue
用于跟踪它们的任何其他资源必须闲置,等待轮到他们。这是浪费资源。不是浪费,但浪费。如果dispatch_queue_t
设置为1,则它一次只会向其mainQueue.maxConcurrentOperationCount
提交一个块,从而阻止GCD无用地分配资源。