I’m trying to understand swift sync/async with the below snippet, but the variables did not add, and the iteration times of the loop varied every time. The outputs were different too.
var mainAsync: Int = 1
var queueAsync: Int = 10
var queueAsyncTwo: Int = 20
var mainAsyncTwo: Int = 30
let queue = DispatchQueue(label:"com")
DispatchQueue.main.async {
for i in 0..<10 { mainAsync += 1 }
}
queue.async {
for i in 0..<10 {
queueAsync += 1
}
}
queue.async {
for i in 0..<10 {
queueAsyncTwo += 1
}
}
for i in 0..<10 {
mainAsyncTwo += 1
}
print("\(mainAsync),-- \(queueAsync),-- \(queueAsyncTwo),--\(mainAsyncTwo)")
The expected outputs:
10,-- 20,-- 30,-- 40
The real outputs varied from time to time like:
1,-- 19,-- 20,--40
1,-- 20,-- 22,--40
1,-- 20,-- 25,--40
I removed the print(thread.current)
. It wasn’t working to represent the loop times.
These are asynchronous operations - they might not have been completed by the time print
is called at the final line. This is a common mistake. For example, the code in this question sends a request to some URL, which is an asynchronous operation. Similar to your code, the code in that question does not wait for the response to be received before printing the contents of the response, and so nothing gets printed.
In particular, the next line after the queue.async { ... }
call is executed immediately after the job is submitted to the queue, not after the job has been completed. Compare this to queue.sync { ... }
which will only return after the job has been completed.
As for the job you scheduled on DispatchQueue.main
, it is never executed. This is because the main
queue is special - it will not execute anything you submit to it unless you do one of the following (from the documentation):
- Calling
dispatchMain()
- Starting your app with a call to
UIApplicationMain(_:_:_:_:)
(iOS) orNSApplicationMain(_:_:)
(macOS)- Using a
CFRunLoop
on the main thread
You did not do any of these things.
Note that the loop that increments mainAsyncTwo
is not a job submitted to the main queue. It is just run in the main thread.
You can do the third bullet point above - run the main RunLoop
for some time before you print:
...
RunLoop.main.run(until: .now.addingTimeInterval(1))
print("\(mainAsync),-- \(queueAsync),-- \(queueAsyncTwo),--\(mainAsyncTwo)")
This not only causes the main
queue to execute its jobs, and also gives enough time for all the queues to finish everything you submitted to them.
Now this prints 11,-- 20,-- 30,--40
.