GCD优先级的意外结果

bcl*_*mer 6 multithreading grand-central-dispatch ios swift

我最近一直在试验GCD优先事项.这是我一直在使用的代码片段.

for _ in 1...1000 {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
        for _ in 1...10000000 {
            let _ = sin(0.64739812)
        }
        print("Finished a default")
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0))     {
            for _ in 1...10000 {
                let _ = sin(0.64739812)
            }
            print("Finished a high")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我希望它能打印出来

Finished a default
Finished a high
// Repeat default and high alternating back and forth 1000 times (because there are 1000 loops)
Run Code Online (Sandbox Code Playgroud)

但实际发生的是打印的日志

Finished a default
Finished a high
Finished a default x 21
Finished a high
Finished a default
Finished a high x 20
Finished a default x 977
Finished a high x 978
Run Code Online (Sandbox Code Playgroud)

它在一开始就有意义,交替一点点.连续21个默认值都有一定意义.但是它在没有处理单个高块的情况下执行977个默认块.我认为这种情况正在发生,因为调度员正忙于处理其他所有事情.但是,它仍然是高优先级队列与默认优先级队列.

有没有人对正在发生的事情有任何见解?

编辑1

for _ in 1...1000 {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
        print("Starting a default")
        for i in 1...10000000 {
            let _ = sin(Double(i))
        }
        print("Finished a default")
    }
}
for _ in 1...1000 {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) {
        print("Starting a high")
        for i in 1...10000000 {
            let _ = sin(Double(i))
        }
        print("Finished a high")
    }
}

print("Done Dispatching Everything")
Run Code Online (Sandbox Code Playgroud)

在这里,我希望在打印之前执行几个defaults和几个highs Done Dispatching Everything,然后执行所有highs然后执行所有defaults.

但是,结果如下:

Starting a default x6
Done Dispatching Everything // at this point, all the high and default blocks have been successfully submitted for execution.
Starting a high
Finished a default
Starting a default
Finished a default
Starting a default
Finished a default
Starting a default
Finished a default
Starting a default
Finished a default
Starting a default
Finished a default
Starting a default
Finished a default
Starting a default
Finished a high
Starting a high
Finished a default
Starting a default
Finished a default
Finished a default
Starting a default
Starting a default
Finished a default
Starting a default
Finished a default
Starting a default
Finished a default
Starting a default
Finished a high
Starting a high
Finished a default
Starting a default
Finished a default
Starting a default
// A sequence that looks like the above for around 1500 lines.
Started+Finished a high x ~500
Run Code Online (Sandbox Code Playgroud)

所以正在发生的事情是,即使在安排了所有事情之后,default发生的事情也远不止于此high.然后在所有defaults完成之后,highs终于开始执行并大量完成.

编辑2

另一块

for _ in 1...1000 {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) {
        print("Starting a high")
        for i in 1...10000000 {
            let _ = sin(Double(i))
        }
        print("Finished a high")
    }
}
for _ in 1...1000 {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
        print("Starting a default")
        for i in 1...10000000 {
            let _ = sin(Double(i))
        }
        print("Finished a default")
    }
}

print("Done Dispatching Everything")
Run Code Online (Sandbox Code Playgroud)

结果让我大吃一惊.它与我的第二个例子(编辑1)完全相同.即使highs都在s之前安排default,它仍然default首先执行块!

编辑3

最后一个例子,我保证

for _ in 1...1000 {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) {
        print("Starting a high")
        for i in 1...10000000 {
            let _ = sin(Double(i))
        }
        print("Finished a high")
    }
}
for _ in 1...1000 {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)) {
        print("Starting a background")
        for i in 1...10000000 {
            let _ = sin(Double(i))
        }
        print("Finished a background")
    }
}

print("Done Dispatching Everything")
Run Code Online (Sandbox Code Playgroud)

这完全按预期执行.所有的highs运行,然后所有backgrounds运行,没有任何例外.然而,这在执行上与编辑2有很大不同,但理论上应该完全相同.

use*_*734 0

检查https://en.wikipedia.org/wiki/Priority_inversion

不要打印到标准输出(将所有打印分派到某个低优先级串行队列)并再次检查所有结果。

在你的游乐场试试这个

import Dispatch

let pq = DispatchQueue(label: "print", qos: .background)
let g = DispatchGroup()
func dprint(_ items: Any...) {
    pq.async(group: g) {
        var r = items.map{ String(describing: $0) }.joined(separator: " ")
        print(r)
    }
}

let q1 = DispatchQueue(label: "q1", qos: .background, attributes: .concurrent)
let q2 = DispatchQueue(label: "q2", qos: .userInteractive, attributes: .concurrent)

for i in 0..<10 {
    q1.async(group: g) {
        dprint("q1", i, "started")
        for i in 0..<100 {
            _ = sin(Double(i))
        }
        dprint("q1", i, "finished")
    }
}
for i in 0..<10 {
    q2.async(group: g) {
        dprint("\tq2", i, "started")
        for i in 0..<100 {
            _ = sin(Double(i))
        }
        dprint("\tq2", i, "finished")
    }
}
g.wait()
print("end of test")
Run Code Online (Sandbox Code Playgroud)

它应该打印(不要期望相同!!)更真实的东西

q1 0 started
q1 1 started
q1 2 started
    q2 0 started
    q2 1 started
    q2 2 started
    q2 3 started
    q2 0 finished
    q2 4 started
    q2 1 finished
    q2 2 finished
    q2 5 started
    q2 6 started
    q2 3 finished
    q2 7 started
    q2 6 finished
    q2 8 started
    q2 5 finished
    q2 7 finished
    q2 4 finished
    q2 9 started
    q2 8 finished
    q2 9 finished
q1 2 finished
q1 3 started
q1 0 finished
q1 4 started
q1 1 finished
q1 6 started
q1 5 started
q1 4 finished
q1 6 finished
q1 7 started
q1 8 started
q1 5 finished
q1 3 finished
q1 9 started
q1 7 finished
q1 8 finished
q1 9 finished
end of test
Run Code Online (Sandbox Code Playgroud)