Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bad precision of usleep when is executed in background thread in Swift

Tags:

ios

swift

usleep

I have been using "usleep" to stop a thread during some milliseconds and I have checked that is stopping more time than expected.

I am sure I am doing something wrong, I am not an expert in Swift, but I don't understand it because it is very easy to check. For example:

DispatchQueue.global(qos: .background).async {
    let timeStart: Int64 = Date().toMillis()
    usleep(20 * 1000) // 20 ms
    let timeEnd: Int64 = Date().toMillis()
    let timeDif = timeEnd - timeStart
    print("start: \(timeStart), end: \(timeEnd), dif: \(timeDif)")
}

The result:

start: 1522712546115, end: 1522712546235, dif: 120

If I execute the same in the main thread:

start: 1522712586996, end: 1522712587018, dif: 22

I think the way I generate the thread is wrong for stopping it. How could I generate a thread that works good with usleep?

Thanks

like image 670
J.S.R - Silicornio Avatar asked Oct 20 '25 05:10

J.S.R - Silicornio


1 Answers

A couple of thoughts:

  1. The responsiveness to usleep is a function of the Quality of Service of the queue. For example, doing thirty 20ms usleep calls on the five queue types, resulting in the following average and standard deviations (measured in ms):

    QoS               mean  stdev
    ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐   ‐‐‐‐‐ ‐‐‐‐‐
    background        99.14 28.06
    utility           74.12 23.66
    default           23.88  1.83
    userInitiated     22.09  1.87
    userInteractive   20.99  0.29
    

    The higher the quality of service, the closer to 20 ms it got, and with a lower standard deviation.

  2. If you want accurate time measurements, you should avoid using Date and/or CFAbsoluteTimeGetCurrent(). As the documentation warns us:

    Repeated calls to this function do not guarantee monotonically increasing results. The system time may decrease due to synchronization with external time references or due to an explicit user change of the clock.

    You can use a mach_time based value, such as conveniently returned by CACurrentMediaTime(), to avoid this problem. For example:

    let start = CACurrentMediaTime()
    // do something
    let elapsed = CACurrentMediaTime() - start
    
  3. If you need even higher accuracy, see Apple Technical Q&A #2169.

like image 52
Rob Avatar answered Oct 21 '25 20:10

Rob



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!