1. Chạy Background:
(0...10).forEach { (value) in DispatchQueue.global(qos: .background).async { print(value) print("This is a \(value * 10)") print("Day la b \(value * 1000)") } }
Nó sẽ in ra 1 cách lộn xộn. async sẽ cho phép chạy concurrent và nó sẽ không đảm bảo result đúng thứ tự.
Kết quả như sau:
01This is a 0This is a 10Day la b 100023This is a 30This is a 20Day la b 20004Day la b 3000Day la b 0This is a 40Day la b 40005This is a 50Day la b 5000
2. Chạy main:
a. async:
(0...5).forEach { (value) in DispatchQueue.main.async { print(value) print("This is a \(value * 10)") print("Day la b \(value * 1000)") } }
Kết quả in ra sẽ là: FIFO
0This is a 0Day la b 01This is a 10Day la b 10002This is a 20Day la b 20003This is a 30Day la b 30004This is a 40Day la b 40005This is a 50Day la b 5000
b. Chạy sync:
(0...5).forEach { (value) in DispatchQueue.main.sync { print(value) print("This is a \(value * 10)") print("Day la b \(value * 1000)") } }
Nó sẽ gây ra một lỗi crash: `error: Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0).
The process has been left at the point where it was interrupted, use "thread return -x" to return to the state before expression evaluation.`
Nguyên nhân như sau:
1. Cái bạn đang làm ở đây là launnch main thread một cách đồng bộ từ background thread trước khi nó tồn tại.
2. Dispatch.main là một serial queue nó có duy nhất một thread để execute tất cả các operations. Nếu ta gọi "sync" queue này, nó sẽ block những operations còn lại để chạy thằng hiện tại và cố execute code bên trong hàm sync.
===
NEVER call the sync function on the main queue
If you call the sync function on the main queue it will block the queue as well as the queue will be waiting for the task to be completed but the task will never be finished since it will not be even able to start due to the queue is already blocked. It is called deadlock.
Two (or sometimes more) items — in most cases, threads — are said to be deadlocked if they all get stuck waiting for each other to complete or perform another action. The first can’t finish because it’s waiting for the second to finish. But the second can’t finish because it’s waiting for the first to finish.
You need to be careful though. Imagine if you call sync and target the current queue you’re already running on. This will result in a deadlock situation.
Use sync to keep track of your work with dispatch barriers, or when you need to wait for the operation to finish before you can use the data processed by the closure.
When to use sync?
When we need to wait until the task is finished. F.e. when we are making sure that some function/method is not double called. F.e. we have synchronization and trying to prevent it to be double called until it's completely finished. When you need to wait for something done on a DIFFERENT queue and only then continue working on your current queue
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 is completed.
An asynchronous function returns immediately, ordering the task to be done but not waiting for it. Thus, an asynchronous function does not block the current thread of execution from proceeding on to the next function.