Он установлен на 1, потому что нет причин устанавливать его на что-либо другое, и, вероятно, лучше оставить его равным 1 по крайней мере по трем причинам, которые я могу придумать.
Причина 1
Поскольку underlyingQueue
для NSOperationQueue.mainQueue
— это dispatch_get_main_queue()
, что является последовательным, NSOperationQueue.mainQueue
фактически является последовательным (он никогда не мог запускать более одного блока за раз, даже если его maxConcurrentOperationCount
было больше 1).
Мы можем проверить это, создав собственную NSOperationQueue
, поместив последовательную очередь в ее целевую цепочку underlyingQueue
и установив для ее maxConcurrentOperationCount
большое число.
Создайте новый проект в Xcode, используя шаблон macOS > Cocoa App с языком Objective-C. Замените реализацию AppDelegate
на это:
@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
Если вы запустите это, вы увидите, что операция 1 не начинается до тех пор, пока не завершится операция 0, даже несмотря на то, что я установил operationQueue.maxConcurrentOperationCount
на 100. Это происходит потому, что в целевой цепочке operationQueue.underlyingQueue
есть последовательная очередь. Таким образом, operationQueue
фактически является последовательным, хотя его maxConcurrentOperationCount
не равно 1.
Вы можете поиграть с кодом, чтобы попытаться изменить структуру целевой цепочки. Вы обнаружите, что если где-то в этой цепочке есть последовательная очередь, то одновременно выполняется только одна операция.
Но если вы установите operationQueue.underlyingQueue = concurrentQueue
и не установите цель concurrentQueue
на serialQueue
, вы увидите, что 64 операции выполняются одновременно. Чтобы operationQueue
выполнял операции одновременно, вся целевая цепочка, начинающаяся с ее underlyingQueue
, должна быть параллельной.
Поскольку основная очередь всегда является последовательной, NSOperationQueue.mainQueue
фактически всегда является последовательной.
На самом деле, если вы установите NSOperationQueue.mainQueue.maxConcurrentOperationCount
в любое значение, кроме 1, это не будет иметь никакого эффекта. Если вы напечатаете NSOperationQueue.mainQueue.maxConcurrentOperationCount
после попытки изменить его, вы обнаружите, что это все еще 1. Я думаю, было бы еще лучше, если бы попытка изменить его вызывала утверждение. Молчаливое игнорирование попыток изменить его, скорее всего, приведет к путанице.
Причина 2
NSOperationQueue
отправляет до maxConcurrentOperationCount
блоков своим underlyingQueue
одновременно. Поскольку mainQueue.underlyingQueue
является последовательным, одновременно может работать только один из этих блоков. После отправки этих блоков может быть слишком поздно использовать сообщение -[NSOperation cancel]
для отмены соответствующих операций. Я не уверен; это деталь реализации, которую я не полностью изучил. В любом случае, если уже слишком поздно, это печально, так как это может привести к пустой трате времени и заряда батареи.
Причина 3
Как и в случае с причиной 2, NSOperationQueue
отправляет до maxConcurrentOperationCount
блоков своему underlyingQueue
одновременно. Поскольку mainQueue.underlyingQueue
является последовательным, только один из этих блоков может выполняться одновременно. Другие блоки и любые другие ресурсы, которые dispatch_queue_t
использует для их отслеживания, должны бездействовать, ожидая своей очереди. Это пустая трата ресурсов. Не большая трата, но все же трата. Если для mainQueue.maxConcurrentOperationCount
установлено значение 1, он будет отправлять только один блок в свой underlyingQueue
за раз, тем самым предотвращая бесполезное выделение ресурсов GCD.
person
rob mayoff
schedule
04.01.2018