In Swift, I used this kind of pattern sometimes.
DispatchQueue.global().async {
// do stuff in background, concurrent thread
DispatchQueue.main.sync {
// update UI
}
}
The purpose of this pattern is clear. Do time consuming calculation in global thread so UI is not locked and update UI in main thread after calculation is done.
What if there's nothing to calculate? I just found a logic in my project which
//A
DispatchQueue.main.sync {
// do something
}
crashes but
// B
DispatchQueue.global().async {
DispatchQueue.main.sync {
// do something
}
}
doesn't crash.
How are they different? And Is case B different with just this?
// C
DispatchQueue.main.async {
// do something
}
And one more question. I know main thread is serial queue, but if I run multiple code block in multiple main.async
, it works like concurrent queue.
DispatchQueue.main.async {
// do A
}
DispatchQueue.main.async {
// do B
}
If main thread is really a serial queue, how can they run simultaneously? If it is just a time slicing than how are they different with global concurrent queue other than main thread can update UI?
x.sync
means that the calling queue will pause and wait until the sync block finishes to continue. so in your example:
DispatchQueue.global().async {
// yada yada something
DispatchQueue.main.sync {
// update UI
}
// this will happen only after 'update UI' has finished executing
}
Usually you don't need to sync
back to main, async is probably good enough and safer to avoid deadlocks. Unless it is a special case where you need to wait until something finishes on main before continuing with your async task.
As for A example crashing - calling sync and targeting current queue is a deadlock (calling queue waits for the sync block to finish, but it does not start because target queue (same) is busy waiting for the sync
call to finish) and thats probably why the crash.
As for scheduling multiple blocks on main queue with async: they won't be run in parallel - they will happen one after another. Also don't assume that queue == thread. Scheduling multiple blocks onto the same queue, might create as many threads as system allow. Just the main queue is special that it utilises Main thread.
Queues
GCD provides three main types of queues:
1. Main queue: runs on the main thread and is a serial queue.
2. Global queues: concurrent queues that are shared by the whole system. There are four such queues with different priorities : high, default, low, and background. The background priority queue has the lowest priority and is throttled in any I/O activity to minimize negative system impact.
3. Custom queues: queues that you create which can be serial or concurrent. Requests in these queues actually end up in one of the global queues.
Synchronous vs. Asynchronous
With GCD, you can dispatch a task either synchronously
or asynchronously
.
A synchronous
function returns control to the caller after the task completes. It blocks the queue and waits until the task is finished. You can schedule a unit of work synchronously by calling DispatchQueue.sync(execute:)
.
An asynchronous
function returns immediately, ordering the task to start but not waiting for it to complete. Thus, an asynchronous function does not block the current thread of execution from proceeding on to the next function. You can schedule a unit of work asynchronously by calling DispatchQueue.async(execute:)
.
Summary
In general, you want to use async
when you need to perform a network-based or CPU-intensive task in the background and not block the current thread.
Here’s a quick guide of how and when to use the various queues with async
:
- Main Queue: This is a common choice to update the UI after completing work in a task on a concurrent queue. To do this, you code one closure inside another. Targeting the main queue and calling
async
guarantees that this new task will execute sometime after the current method finishes. - Global Queue: This is a common choice to perform non-UI work in the background.
- Custom Serial Queue: A good choice when you want to perform background work serially and track it. This eliminates resource contention and race conditions since you know only one task at a time is executing. Note that if you need the data from a method, you must declare another closure to retrieve it or consider using
sync
.
Common mistake:
Call DispatchQueue.main.sync
from the main
queue as a result the app will be frozen because the calling queue(main
) will wait until the dispatched block is finished, but it(dispatched block) will not be even able to start (because the main
queue was stopped and waiting)
The source is here
SO answer about Asynchronous vs synchronous execution
来源:https://stackoverflow.com/questions/42772907/what-does-main-sync-in-global-async-mean