Confused about Operation and OperationQueue QoS relationship

不想你离开。 提交于 2021-02-11 06:29:35

问题


The OperationQueue documentation states for the qualityOfService property:

This property specifies the service level applied to operation
objects added to the queue

However one can simply check that this is not true by just copy & pasting the code below into a new playground.

import Foundation

let q = OperationQueue()
q.qualityOfService = .userInitiated

print("QUEUE", q.qualityOfService.rawValue)

let op = BlockOperation()
op.addExecutionBlock {
    print("OP", op.qualityOfService.rawValue)
}

q.addOperations([op], waitUntilFinished: true)

You will see that the queues QoS level is 25/.userInitiated and the operations -1/.default.

So does it mean that the operations QoS level is .default in relation to the queues elevanted .userInitiated level, or is it .default, despite the queue having a higher QoS level?

What I actually expect is that these 2 values should be the same.

PS: I need to invoke a Process inside the Operation, which in turn also has a qualityOfService setting that should be the same as the queue/ops.


回答1:


The operation’s qualityOfService indicates whether the operation, itself, needs to dictate a particular QoS. But -1/.default effectively means that it will just use the QoS for the queue (and thus that of the worker thread that is used). I would not be terribly concerned about the QoS of the operation. What you care about is the QoS of the thread on which it runs:

let q = OperationQueue()
q.qualityOfService = .userInitiated

print("CURRENT", Thread.current.qualityOfService.rawValue)     // CURRENT 33
print("QUEUE", q.qualityOfService.rawValue)                    // QUEUE 25

let op = BlockOperation {
    print("THREAD", Thread.current.qualityOfService.rawValue)  // THREAD 25
}

q.addOperations([op], waitUntilFinished: false)

As you can see, the QoS for the thread that is running the code is precisely what you would expect it to be.


If you want, you can see how changing the operation’s QoS to something higher than the queue will affect the QoS of the worker thread upon which it runs. Thus, background QoS queue with no QoS specified for the operation:

let q = OperationQueue()
q.qualityOfService = .background

print("CURRENT", Thread.current.qualityOfService.rawValue)    // CURRENT 33
print("QUEUE", q.qualityOfService.rawValue)                   // QUEUE 9

let op = BlockOperation()
op.addExecutionBlock {
    print("OP", op.qualityOfService.rawValue)                 // OP -1
    print("THREAD", Thread.current.qualityOfService.rawValue) // THREAD 9
}

q.addOperations([op], waitUntilFinished: false)

But you can, if you want, specify a particular QoS for the operation, in this case escalating it to a higher QoS:

let q = OperationQueue()
q.qualityOfService = .background

print("CURRENT", Thread.current.qualityOfService.rawValue)    // CURRENT 33
print("QUEUE", q.qualityOfService.rawValue)                   // QUEUE 9

let op = BlockOperation()
op.qualityOfService = .userInitiated                          // change op’s QoS, and thus the worker thread to a higher QoS, too
op.addExecutionBlock {
    print("OP", op.qualityOfService.rawValue)                 // OP 25
    print("THREAD", Thread.current.qualityOfService.rawValue) // THREAD 25
}

q.addOperations([op], waitUntilFinished: false)



回答2:


There is documentation about the operation's inference of QoS from the queue (Section "Quality of Service Inference and Promotion").

The particular case of yours is described there as:

Any of the queue’s operations with a lower QoS are promoted to the higher QoS. Any operations with a lower QoS that are added to the queue in the future will infer the higher QoS.

However, this does not mean that op.qualityOfService property is modified by the OperationQueue, because that would erase the QoS that you assigned to the operation. In other words, the value of the op.qualityOfService might not represent the promoted QoS, only the one that you assigned (or .default).

According to swift's implementation of Operation.swift, the op.queuePriority is the property that represents the actual priority in the queue, after all the complicated logic of QoS inference and promotion is applied. You can map it back to QoS, same way as it's done forwards in the code I've just referred



来源:https://stackoverflow.com/questions/66051129/confused-about-operation-and-operationqueue-qos-relationship

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!