NSOperationQueue.qualityOfService
的文档说:
此属性指定应用于操作对象的服务级别已添加到队列如果操作对象具有显式服务级别集,则使用该值
它没有提到操作和队列之间的相对质量,所以任何组合都应该有效。
然而,GCD
有一些相应的功能,其文档称:
DISPATCH_BLOCK_FORCE_QOS_CLASS
指示调度块对象的执行提交到队列应该优选分配给块的QOS类(resp。与提交时的块相关联)类,只要这样做就不会导致较低的QOS级别。
如果NSOperation
和NSOperationQueue
构建在GCD
之上——我相信这是真的——那么限制似乎也应该适用于它们。
那么,如果我将具有较低qualityOfService
的NSOperation
添加到NSOperationQueue
,它会使用自己的较低qualityOfService
还是队列的较高qualityOfService
运行?
感谢@das为我介绍OS X v10.10的Foundation Release Notes。
忽略操作依赖部分,NSOperation
和NSOperationQueue
之间的QoS规则与调度块和调度队列之间的规则完全相同——尽管@das指出"NSOperationQueue的QoS实现不是建立在GCD QoS块原语之上的",但规则实际上是相同的,也就是说,NSOperation
的QoS(如果更低)将提高到NSOperationQueue
的QoS。所以我最初的猜测是正确的。NSOperationQueue.qualityOfService
的单据错误:
如果操作对象设置了明确的服务级别,则该值而是使用。
以下是对NSOperation
和NSOperationQueue
的QoS规则的详细解释:
NSOperationQueue服务质量
NSOperationQueue具有新的qualityOfService属性。
您可以随时更改qualityOfService属性。
当一个操作被添加到队列中时,队列当时的服务质量值可能会影响操作将在以下条件下运行的有效QOS:
- 如果尚未设置队列属性,则操作不受影响
- 如果队列属性已设置为NSQualityOfServiceDefault,则操作不受影响
- 如果将队列属性设置为另一个值,则如果队列的提升QOS尚未达到该级别,则该操作将提升到队列的qualityOfService
如果在队列中有操作时更改了队列的qualityOfService属性,则队列中操作的有效QOS将受到影响,就像将操作添加到队列时一样。因此,当队列的qualityOfService属性发生更改时,队列中的所有操作,无论是否运行,其有效QOS都会提升到该级别(如果它们较低),并且将来添加到队列的操作会提升到那个级别(当它们较低时)。如果qualityOfService属性从一个级别降低到另一个级别,则只有将来的添加才会受到新的较低值的影响。队列的qualityOfService的设置或设置值永远不会降低操作的提升或有效QOS。
当一个操作被添加到队列中时,该操作当时的有效QOS值可能会影响已经在队列中的操作("在它前面")的有效QOS:
- 新添加操作队列中已经在前面的操作,无论是否正在运行,都将提升为正在添加的操作的有效QOS
因此,如果将高QOS操作添加到队列中,则队列中已经存在的操作将提升到该级别(如果它们更低)。在该高QOS操作之后添加的操作不受其在队列中的存在的影响。
NSOperation qualityOfService一节讨论了运营促进QOS和有效QOS的含义和相互作用。
NSOperationQueues不会从任何执行上下文推断任何QOS。
如果设置了NSOperationQueue的(dispatch_queue_t)underlyingQueue属性,则NSOperationQueues和NSOperations的qualityOfService属性值无效。该队列运行的操作的有效QOS由dispatch_queue_t的状态决定。
NS服务运营质量
NSOperation具有新的qualityOfService属性。
您可以随时更改qualityOfService属性。
有各种真实和虚拟的QOS值与操作的运行方式有关:
- qualityOfService属性值
- 推断的QOS
- 促销QOSes
- 有效的QOS
创建操作对象时,根据执行上下文计算推断的QOS值:
- 如果:
- 操作是在另一个操作(已经在该线程上运行)的执行上下文中创建的;或
- 所述操作是在特定NSProcessInfo API的执行上下文中创建的;则使用与当前线程的调用堆栈的当前激活帧最近的一个作为新操作的推断QOS:
- 该操作在开始运行时的有效QOS
- NSProcessInfo API的值被映射到QOS值
- 如果在主线程上创建操作,则推断出的QOS为NSQualityOfServiceUserInitiated
- 否则,读取当前线程的QOS(可能为零),并将其用作新操作的推断QOS
一项操作可以在以下几种情况下进行推广(应用推广QOSe):
- 将操作添加到队列时,或更改操作所在队列的qualityOfService属性时
- (如NSOperationQueue部分所述)
- 当将不同的操作添加到队列时问题)已经在
- (如NSOperationQueue部分所述)
- 当同一队列中的另一个稍后(在所讨论的操作之后)操作引发其有效QOS时
- 其他操作的有效QOS促进了操作
- 当不同的操作(被依赖方)依赖于所讨论的操作时
- 受试者的有效生活质量促进了手术
- 当被依赖方操作的有效QOS提高时
- 受试者新的有效生活质量促进了手术
- 当使用-waitUntilFinished方法等待操作时,或间接地当使用操作队列的-waitUnitilAllOperationsAreFinished法时
- 如果等待线程是主线程,则升级QOS取为NSQualityOfServiceUserInteractive
- 否则,如果等待是在另一个操作的执行上下文中完成的,则其有效QOS促进该操作
- 否则当前线程的QOS将促进该操作
这些统称为促销QOSe;或者对于所有这些中的MAX(),只是提升QOS。
这些不同的值被组合成有效的QOS。有效的QOS是所有这些QOS值的MAX():{推断的QOS、促销QOSes、qualityOfService属性值},具有以下条件:
- 如果操作的qualityOfService属性已显式设置为任何值,甚至NSQualityOfServiceDefault,则会忽略推断的QOS
- 如果操作的qualityOfService属性没有显式设置为任何值,则会忽略它(就好像不存在值一样)
- NSQualityOfServiceDefault的所有QOS值都将被忽略
- 如果忽略之后没有QOS值,则有效的QOS为NSQualityOfServiceDefault
因此,例如,如果一个操作被等待,它的有效QOS可以由等待上下文引发,等待上下文可以递归地引发它的所有依赖操作和队列中在它前面的所有操作(依此类推,在这些关系的树中递归地向外)。
如果操作是手动启动的,而不是放在NSOperationQueue中,则操作的qualityOfService属性值无效,除非启动该操作的代码读取该值并适当地使用它;这超出了基金会的职权范围。
NSOperationQueue的QoS实现是而不是构建在GCD QoS块基元之上。
NSOperationQueue行为在Foundation发行说明中有详细说明。
对于GCD队列,当执行具有分配或传播QoS的块时,QoS降低的唯一时间是当该块提交到的队列具有未指定的QoS时(创建的队列没有QoS属性,并且没有针对非默认全局队列)。在这种情况下,队列最初由QoS类默认值的工作线程提供服务,并且允许降低。
有关更多详细信息,请参阅dispatch/block.h
标题中的文档或2015年和2014年的GCD WWDC会议。
spindump的时间轴模式将显示采样进程线程的QoS。您可能需要设计一些东西,让spindump告诉您发生了什么,并让您了解QoS提升的工作原理。QoS提升的理念是防止优先级倒置,这样用户启动的操作就不会被耗尽。