Swift App Using Dispatchqueue.Concurrentperform(Iterations:) No Longer Runs Concurrently Under MAC Os Sierra

C++11 app that uses dispatch_apply not working under Mac OS Sierra

I'm not sure if it is a bug in Sierra or not. But it seems to work if you explicitly associate a global concurrent queue as target:

dispatch_queue_t target =
dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0);
dispatch_queue_t workQueue =
dispatch_queue_create_with_target("workQueue", DISPATCH_QUEUE_CONCURRENT, target);
// ^~~~~~~~~~~ ^~~~~~

DispatchQueue: why does serial complete faster than concurrent?

There are two issues:

  1. I’d avoid doing print inside the loop. That’s synchronized and you’re likely to experience greater performance degradation in concurrent implementation. That’s not the whole story here, but it doesn’t help.

  2. Even after removing the print from within the loop, 50,000 increments of the counter is simply not enough work to see the benefit of concurrentPerform. As Improving on Loop Code says:

    ... And although this [concurrentPerform] can be a good way to improve performance in loop-based code, you must still use this technique discerningly. Although dispatch queues have very low overhead, there are still costs to scheduling each loop iteration on a thread. Therefore, you should make sure your loop code does enough work to warrant the costs. Exactly how much work you need to do is something you have to measure using the performance tools.

    On debug build, I needed to increase number of iterations to values closer to 5,000,000 before this overhead was overcome. And on release build, even that wasn’t sufficient. A spinning loop and incrementing a counter is just too quick to offer meaningful analysis of concurrent behavior.

    So, in my example below, I replaced this spinning loop with a more computationally intensive calculation (calculating π using a historic, but not terribly efficient, algorithm).

As an aside:


  1. Rather than measuring the performance yourself, if you do this within a XCTestCase unit test, you can use measure to benchmark performance. This repeats the benchmarking multiple times, captures elapsed time, averages the results, etc. Just make sure to edit your scheme so the test action uses an optimized “release” build rather than a “debug” build.

  2. There’s no point in dispatching this to a global queue if you’re going to use dispatch group to make the calling thread wait for it to complete.

  3. You don’t need to use dispatch groups to wait for concurrentPerform to finish, either. It runs synchronously.

    As the concurrentPerform documentation says:

    The dispatch queue executes the submitted block the specified number of times and waits for all iterations to complete before returning.

  4. It’s not really material, but it’s worth noting that your for _ in 0...10 { ... } is doing 11 iterations, not 10. You obviously meant to use ..<.

Thus, here is an example, putting it in a unit test, but replacing the “heavy” calculation with something more computationally intensive:

class MyAppTests: XCTestCase {

// calculate pi using Gregory-Leibniz series

func calculatePi(iterations: Int) -> Double {
var result = 0.0
var sign = 1.0
for i in 0 ..< iterations {
result += sign / Double(i * 2 + 1)
sign *= -1
}
return result * 4
}

func performHeavyTask(iteration: Int) {
let pi = calculatePi(iterations: 100_000_000)

print(iteration, .pi - pi)
}

func testSerial() {
measure {
for i in 0..<10 {
self.performHeavyTask(iteration: i)
}
}
}

func testConcurrent() {
measure {
DispatchQueue.concurrentPerform(iterations: 10) { i in
self.performHeavyTask(iteration: i)
}
}
}
}

On my MacBook Pro 2018 with 2.9 GHz Intel Core i9, with a release build the concurrent test took, on average, 0.247 seconds, whereas the serial test took roughly four times as long, 1.030 seconds.

Find two consecutive rows

Assuming the rows have sequential IDs, something like this may be what you're looking for:

select top 1 * 
from
Bills b1
inner join Bills b2 on b1.id = b2.id - 1
where
b1.IsEstimate = 1 and b2.IsEstimate = 1
order by
b1.BillDate desc


Related Topics



Leave a reply



Submit