GCD queue usage
file
First look at the official documents. DispatchQueue is a class object, which inherits from DispatchObject;
DispatchObject implements OS_ Method in object, guess OS_object may be a protocol, which is not found in the document
First look at DispatchObject:
func activate() Activates the dispatch object. func resume() Resumes the invocation of block objects on a dispatch object. func suspend() Suspends the invocation of block objects on a dispatch object. func setTarget(queue: DispatchQueue?) Specifies the dispatch queue on which to perform work associated with the current object. enum DispatchPredicate Logical conditions to evaluate within a given execution context. func dispatchPrecondition(condition() -> DispatchPredicate) Checks a dispatch condition necessary for further execution.
That is to say, as a queue, DispatchQueue also implements the above method. In addition, it also implements the following method
class var main: DispatchQueue The dispatch queue associated with the main thread of the current process. class func global(qos: DispatchQoS.QoSClass) -> DispatchQueue Returns the global system queue with the specified quality-of-service class. init(label: String, qos: DispatchQoS, attributes: DispatchQueue.Attributes, autoreleaseFrequency: DispatchQueue.AutoreleaseFrequency, target: DispatchQueue?) Creates a new dispatch queue to which you can submit blocks. enum DispatchQoS.QoSClass Quality-of-service classes that specify the priorities for executing tasks. struct DispatchQueue.Attributes Attributes that define the behavior of a dispatch queue. enum DispatchQueue.AutoreleaseFrequency Constants indicating the frequency with which a dispatch queue autoreleases objects. class OS_dispatch_queue_main A system-provided dispatch queue that schedules tasks for serial execution on the app's main thread. class OS_dispatch_queue_global A system-provided dispatch queue that schedules tasks for concurrent execution. class OS_dispatch_queue_serial A custom dispatch queue that schedules tasks for serial execution on an arbitrary thread. class OS_dispatch_queue_concurrent A custom dispatch queue that schedules tasks for concurrent execution.
According to the document:
- DispatchQueue is a first in first out queue. When users submit tasks to the queue, the queue will schedule the tasks to the threads in the thread pool for execution
- Tasks submitted by users can be executed synchronously or asynchronously, serially or asynchronously. Tasks in mainQueue can only be executed serially
Document reminder:
When using queues, you need to avoid creating too many threads:
- Avoid the execution of block tasks when executing tasks in the concurrent queue, because the scheduling system will continue to create threads in this scenario
- Avoid creating your own queue, because creating your own queue will consume thread resources. You should point to globalQueue by setting targetQueue to avoid creating too many threads
practice
Create different queues
- Main queue: dispatchqueue main
- Global queue: dispatchqueue global()
- Self built serial queue: dispatchqueue init(label: “test.serial.queue”)
- Self built concurrent queue: dispatchqueue init(label: “test.serial.queue”, attributes: .concurrent)
import Foundation func createQueue() { ///Main line let mainQueue = DispatchQueue.main print(mainQueue) // <OS_dispatch_queue_main: com.apple.main-thread> /* class func global(qos: DispatchQoS.QoSClass = .default) -> DispatchQueue The default priority is default, and globalQueue is a concurrent queue */ let globalQueue = DispatchQueue.global() print(globalQueue) // <OS_dispatch_queue_global: com.apple.root.default-qos> ///Create custom queue, serial let customSerialQueue = DispatchQueue.init(label: "test.serial.queue") print(customSerialQueue) /* Create a concurrent queue. No priority is specified at this time. The priority is You can specify whether it is concurrent, not the default serial. In addition, you can specify that the new queue is inactive static let concurrent: DispatchQueue.Attributes The queue schedules tasks concurrently. static let initiallyInactive: DispatchQueue.Attributes The newly created queue is inactive. */ let customCurrentQueue = DispatchQueue.init(label: "test.serial.queue", attributes: .concurrent) print(customCurrentQueue) } createQueue()
Use home queue
The main queue is mainly used when the task needs to be executed by the main thread
Asynchronous tasks can be executed concurrently on the main thread
Synchronizing sync in the main thread to execute the tasks of the main queue will lead to deadlock
import Foundation /* result: useMainQueue start useMainQueue end useMainQueue task excuting */ func useMainQueue1() { ///Main line print("useMainQueue start") let mainQueue = DispatchQueue.main mainQueue.async { print("useMainQueue task excuting") } print("useMainQueue end") } // useMainQueue1() /* result: useMainQueue start useMainQueue end useMainQueue2 start [2] 54143 illegal hardware instruction ./task */ func useMainQueue2() { ///Main line print("useMainQueue2 start") let mainQueue = DispatchQueue.main mainQueue.sync { print("useMainQueue2 task excuting") } print("useMainQueue2 end") } // useMainQueue2() /* result: useMainQueue3 start useMainQueue3 task excuting useMainQueue3 end */ func useMainQueue3() { ///Main line print("useMainQueue3 start") let mainQueue = DispatchQueue.main mainQueue.sync { print("useMainQueue3 task excuting") } print("useMainQueue3 end") } DispatchQueue.global().async { useMainQueue3() } RunLoop.main.run()
Use global queue
@objc func test() { print("\n\n") DispatchQueue.global(qos: .default).async { print("default", Thread.current) } DispatchQueue.global(qos: .background).async { print("background", Thread.current) } DispatchQueue.global(qos: .unspecified).async { print("unspecified", Thread.current) } DispatchQueue.global(qos: .userInitiated).async { print("userInitiated", Thread.current) } DispatchQueue.global(qos: .utility).async { print("utility", Thread.current) } DispatchQueue.global(qos: .userInteractive).async { print("userInteractive", Thread.current) } }
result
default <NSThread: 0x600003255400>{number = 4, name = (null)} utility <NSThread: 0x6000032483c0>{number = 7, name = (null)} unspecified <NSThread: 0x60000323a3c0>{number = 8, name = (null)} userInteractive <NSThread: 0x60000322f000>{number = 9, name = (null)} userInitiated <NSThread: 0x6000032416c0>{number = 10, name = (null)} background <NSThread: 0x6000032483c0>{number = 7, name = (null)} default <NSThread: 0x6000032416c0>{number = 10, name = (null)} userInteractive <NSThread: 0x600003252140>{number = 12, name = (null)} unspecified <NSThread: 0x60000322ec40>{number = 11, name = (null)} userInitiated <NSThread: 0x6000032416c0>{number = 10, name = (null)} utility <NSThread: 0x6000032416c0>{number = 10, name = (null)} background <NSThread: 0x6000032416c0>{number = 10, name = (null)} default <NSThread: 0x6000032416c0>{number = 10, name = (null)} unspecified <NSThread: 0x600003232f80>{number = 14, name = (null)} userInteractive <NSThread: 0x60000327c380>{number = 13, name = (null)} userInitiated <NSThread: 0x6000032416c0>{number = 10, name = (null)} utility <NSThread: 0x60000327c380>{number = 13, name = (null)} background <NSThread: 0x6000032416c0>{number = 10, name = (null)} default <NSThread: 0x60000327c380>{number = 13, name = (null)} unspecified <NSThread: 0x600003232f80>{number = 14, name = (null)} userInteractive <NSThread: 0x600003241ec0>{number = 15, name = (null)} userInitiated <NSThread: 0x600003227fc0>{number = 16, name = (null)} utility <NSThread: 0x600003227fc0>{number = 16, name = (null)} background <NSThread: 0x6000032416c0>{number = 10, name = (null)} default <NSThread: 0x600003227fc0>{number = 16, name = (null)} userInteractive <NSThread: 0x600003241ec0>{number = 15, name = (null)} unspecified <NSThread: 0x600003232f80>{number = 14, name = (null)} userInitiated <NSThread: 0x60000327c380>{number = 13, name = (null)} utility <NSThread: 0x6000032416c0>{number = 10, name = (null)} background <NSThread: 0x6000032416c0>{number = 10, name = (null)} default <NSThread: 0x6000032416c0>{number = 10, name = (null)} unspecified <NSThread: 0x60000327c380>{number = 13, name = (null)} userInteractive <NSThread: 0x600003241ec0>{number = 15, name = (null)} userInitiated <NSThread: 0x600003227fc0>{number = 16, name = (null)} utility <NSThread: 0x600003232f80>{number = 14, name = (null)} background <NSThread: 0x60000327c380>{number = 13, name = (null)} default <NSThread: 0x600003232f80>{number = 14, name = (null)} unspecified <NSThread: 0x600003227fc0>{number = 16, name = (null)} userInteractive <NSThread: 0x600003241ec0>{number = 15, name = (null)} userInitiated <NSThread: 0x6000032416c0>{number = 10, name = (null)} utility <NSThread: 0x60000327c380>{number = 13, name = (null)} background <NSThread: 0x600003241ec0>{number = 15, name = (null)} default <NSThread: 0x60000327c380>{number = 13, name = (null)} unspecified <NSThread: 0x6000032416c0>{number = 10, name = (null)} userInteractive <NSThread: 0x600003227fc0>{number = 16, name = (null)} userInitiated <NSThread: 0x600003232f80>{number = 14, name = (null)} utility <NSThread: 0x600003241ec0>{number = 15, name = (null)} background <NSThread: 0x600003227fc0>{number = 16, name = (null)}
The old version can specify 4 priorities
@objc func test() { print("\n\n") /// high > default > low > background /// 'global(priority:)' was deprecated in iOS 8.0 DispatchQueue.global(priority: .low).async { print("low", Thread.current) } DispatchQueue.global(priority: .default).async { print("default", Thread.current) } DispatchQueue.global(priority: .background).async { print("background", Thread.current) } DispatchQueue.global(priority: .high).async { print("high", Thread.current) } }
result
default <NSThread: 0x600002b511c0>{number = 7, name = (null)} high <NSThread: 0x600002b33900>{number = 5, name = (null)} low <NSThread: 0x600002b75d40>{number = 6, name = (null)} background <NSThread: 0x600002b505c0>{number = 4, name = (null)} default <NSThread: 0x600002b75d40>{number = 6, name = (null)} high <NSThread: 0x600002b505c0>{number = 4, name = (null)} low <NSThread: 0x600002b33900>{number = 5, name = (null)} background <NSThread: 0x600002b511c0>{number = 7, name = (null)} default <NSThread: 0x600002b511c0>{number = 7, name = (null)} high <NSThread: 0x600002b33900>{number = 5, name = (null)} low <NSThread: 0x600002b33900>{number = 5, name = (null)} background <NSThread: 0x600002b505c0>{number = 4, name = (null)} default <NSThread: 0x600002b33900>{number = 5, name = (null)} high <NSThread: 0x600002b511c0>{number = 7, name = (null)} low <NSThread: 0x600002b505c0>{number = 4, name = (null)} background <NSThread: 0x600002b511c0>{number = 7, name = (null)} default <NSThread: 0x600002b505c0>{number = 4, name = (null)} high <NSThread: 0x600002b75d40>{number = 6, name = (null)} low <NSThread: 0x600002b511c0>{number = 7, name = (null)} background <NSThread: 0x600002b33900>{number = 5, name = (null)} default <NSThread: 0x600002b511c0>{number = 7, name = (null)} high <NSThread: 0x600002b75d40>{number = 6, name = (null)} low <NSThread: 0x600002b33900>{number = 5, name = (null)} background <NSThread: 0x600002b505c0>{number = 4, name = (null)} default <NSThread: 0x600002b33900>{number = 5, name = (null)} high <NSThread: 0x600002b511c0>{number = 7, name = (null)} low <NSThread: 0x600002b505c0>{number = 4, name = (null)} background <NSThread: 0x600002b75d40>{number = 6, name = (null)} default <NSThread: 0x600002b75d40>{number = 6, name = (null)} high <NSThread: 0x600002b505c0>{number = 4, name = (null)} low <NSThread: 0x600002b505c0>{number = 4, name = (null)} background <NSThread: 0x600002b511c0>{number = 7, name = (null)} default <NSThread: 0x600002b511c0>{number = 7, name = (null)} high <NSThread: 0x600002b33900>{number = 5, name = (null)} low <NSThread: 0x600002b505c0>{number = 4, name = (null)} background <NSThread: 0x600002b75d40>{number = 6, name = (null)} default <NSThread: 0x600002b75d40>{number = 6, name = (null)} high <NSThread: 0x600002b505c0>{number = 4, name = (null)} low <NSThread: 0x600002b33900>{number = 5, name = (null)} background <NSThread: 0x600002b505c0>{number = 4, name = (null)} default <NSThread: 0x600002b505c0>{number = 4, name = (null)} high <NSThread: 0x600002b33900>{number = 5, name = (null)} low <NSThread: 0x600002b511c0>{number = 7, name = (null)} background <NSThread: 0x600002b33900>{number = 5, name = (null)} default <NSThread: 0x600002b33900>{number = 5, name = (null)} high <NSThread: 0x600002b511c0>{number = 7, name = (null)} low <NSThread: 0x600002b511c0>{number = 7, name = (null)} background <NSThread: 0x600002b505c0>{number = 4, name = (null)} default <NSThread: 0x600002b505c0>{number = 4, name = (null)} high <NSThread: 0x600002b511c0>{number = 7, name = (null)} low <NSThread: 0x600002b33900>{number = 5, name = (null)} background <NSThread: 0x600002b511c0>{number = 7, name = (null)} low <NSThread: 0x600002b511c0>{number = 7, name = (null)} default <NSThread: 0x600002b33900>{number = 5, name = (null)} high <NSThread: 0x600002b505c0>{number = 4, name = (null)} background <NSThread: 0x600002b511c0>{number = 7, name = (null)} default <NSThread: 0x600002b511c0>{number = 7, name = (null)} high <NSThread: 0x600002b75d40>{number = 6, name = (null)} low <NSThread: 0x600002b75d40>{number = 6, name = (null)} background <NSThread: 0x600002b75d40>{number = 6, name = (null)} default <NSThread: 0x600002b75d40>{number = 6, name = (null)} low <NSThread: 0x600002b505c0>{number = 4, name = (null)} high <NSThread: 0x600002b511c0>{number = 7, name = (null)} background <NSThread: 0x600002b33900>{number = 5, name = (null)} default <NSThread: 0x600002b33900>{number = 5, name = (null)} high <NSThread: 0x600002b505c0>{number = 4, name = (null)} low <NSThread: 0x600002b505c0>{number = 4, name = (null)} background <NSThread: 0x600002b511c0>{number = 7, name = (null)} default <NSThread: 0x600002b511c0>{number = 7, name = (null)} high <NSThread: 0x600002b505c0>{number = 4, name = (null)} low <NSThread: 0x600002b505c0>{number = 4, name = (null)} background <NSThread: 0x600002b33900>{number = 5, name = (null)} default <NSThread: 0x600002b33900>{number = 5, name = (null)} high <NSThread: 0x600002b511c0>{number = 7, name = (null)} low <NSThread: 0x600002b505c0>{number = 4, name = (null)} background <NSThread: 0x600002b75d40>{number = 6, name = (null)} low <NSThread: 0x600002b75d40>{number = 6, name = (null)} default <NSThread: 0x600002b505c0>{number = 4, name = (null)} high <NSThread: 0x600002b511c0>{number = 7, name = (null)}
Number of threads that GCD can create
According to the data, gcd is internally limited to 512 threads, plus the other four threads, 516 threads
Special note here: The 512 mentioned is the limit of gcd. After the 512 gcd threads are opened, you can still open them with NSThread. So the chart above Currently it should be 512, 516 = 512(max) + main thread + js thread + web thread + uikit event thread" https://stackoverflow.com/questions/7213845/number-of-threads-created-by-gcd
Topic analysis
- Output results of the following topics
class ViewController: UIViewController { var number: Int = 0 override func viewDidLoad() { super.viewDidLoad() let button = UIButton() button.setTitle("Test", for: .normal) button.setTitleColor(.red, for: .normal) button.sizeToFit() button.addTarget(self, action: #selector(test), for: .touchUpInside) view.addSubview(button) button.center = view.center } @objc func test() { while number < 5 { DispatchQueue.global().async { self.number += 1 } } print(number) } }
Theoretical results, number > = 5; The actual test is about 14 and 15
- Output results of the following topics (replace the above test method with the following method)
@objc func test() { number = 0 for _ in 1...1000 { DispatchQueue.global().async { self.number += 1 } } print(number) }
Theoretical results, 0 < = number < = 1000 > & &; Actual test results
994 996 987 993 977 996 993
- What is the final output order of the following methods
@objc func test() { let queue = DispatchQueue.init(label: "test", qos: .default, attributes: .concurrent) queue.async { print(1) } queue.async { print(2) } queue.sync { print(3) } print(0) queue.async { print(4) } queue.async { print(5) } queue.async { print(6) } }
The theoretical results show that 3 is before 0 and 0 is before 456; actual
3 0 1 2 4 6 5
- What is the output of the following questions?
@objc func test() { print("\n\n") let queue = DispatchQueue.init(label: "test", qos: .default, attributes: .concurrent) print(1) queue.async { print(2) queue.async { print(3) } Thread.sleep(forTimeInterval: 0.5) print(4) } Thread.sleep(forTimeInterval: 0.5) print(5) }
Theoretical results: the first output 1, 2 is before 34, and the order of 3 and 4 is uncertain; The sequence between 5 and 234 is uncertain;
Actual test: 15243 if there is no delay, 12354 if there is delay