I, too, get times around 120 ms when sleeping a thread on a background queue:
import Foundation
DispatchQueue.global(qos: .background).async {
let timeStart = Date()
usleep(20 * 1000) // 20 ms
let timeEnd = Date()
let timeDif = timeEnd.timeIntervalSince(timeStart) * 1000
print("start: \(timeStart), end: \(timeEnd), dif: \(timeDif)")
exit(0)
}
CFRunLoopRun()
outputs:
start: 2018-04-03 00:10:54 +0000, end: 2018-04-03 00:10:54 +0000, dif: 119.734048843384
However, with default QoS, my results are consistently closer to 20 ms:
import Foundation
DispatchQueue.global(qos: .default).async {
let timeStart = Date()
usleep(20 * 1000) // 20 ms
let timeEnd = Date()
let timeDif = timeEnd.timeIntervalSince(timeStart) * 1000
print("start: \(timeStart), end: \(timeEnd), dif: \(timeDif)")
exit(0)
}
CFRunLoopRun()
start: 2018-04-03 00:12:15 +0000, end: 2018-04-03 00:12:15 +0000, dif: 20.035982131958
So it appears that the .background
QoS is causing the behavior you are seeing. Although I don't have direct knowledge of why this would be, it doesn't seem too far-fetched to speculate that the OS may be somewhat more lax about waking up sleeping threads that are marked with a background QoS. Indeed, this is what Apple's documentation has to say about it:
A quality of service (QoS) class allows you to categorize work to be performed by NSOperation, NSOperationQueue, NSThread objects, dispatch queues, and pthreads (POSIX threads). By assigning a QoS to work, you indicate its importance, and the system prioritizes it and schedules it accordingly. For example, the system performs work initiated by a user sooner than background work that can be deferred until a more optimal time. In some cases, system resources may be reallocated away from the lower priority work and given to the higher priority work.
The possibility for your background work to be "deferred until a more optimal time" seems a plausible explanation of the behavior you're seeing.