作为一名从OC过来的iOS程序员,对于OC的GCD肯定不会陌生,在项目中也会经常用到,一套漂亮的C函数,用起来得心应手,而到了swift,GCD变得更加面向对象,虽然原理一样,但是API却有较大变化。
下面就跟随笔者来看一下吧。
类或属性
|
描述
|
class DispatchQueue
|
一个可以在应用程序的主线程或后台线程上连续或并发地管理任务的执行的对象。
|
class DispatchWorkItem
|
要执行的任务,允许进行完成处理和执行依赖的封装。
|
class DispatchGroup
|
一个可以单独监测的任务组。
|
struct DispatchQoS
|
应用于任务的服务质量或执行优先级。
|
class DispatchSource
|
协调处理特定低级系统事件(如文件系统事件、定时器和UNIX信号)的对象。
|
class DispatchIO
|
使用基于流或随机访问语义管理文件描述符上的操作的对象。
|
struct DispatchData
|
管理基于内存的数据缓冲区并将其公开为连续内存块的对象。
|
struct DispatchDataIterator
|
在分派数据对象的内容上的逐字节迭代器。
|
class DispatchSemaphore
|
一个通过使用传统的计数信号量来控制跨多个执行上下文对资源的访问的对象。
|
struct DispatchTime
|
相对于默认时钟的时间点,精度为纳秒。
|
struct DispatchWallTime
|
根据挂钟显示的绝对时间点,具有微秒精度。
|
enum DispatchTimeInterval
|
关于时间的枚举值。
|
enum DispatchTimeoutResult
|
一个指示被分发的任务是否在制定的时间完成的结果值。
|
typealias dispatch_time_t
|
typealias dispatch_time_t = UInt64
|
var DISPATCH_WALLTIME_NOW: UInt
|
当前时间
|
class DispatchObject
|
大多数dispatch类型的基类。
|
enum DispatchPredicate
|
在给定执行上下文中计算的逻辑条件。
|
func dispatchPrecondition(condition() -> DispatchPredicate)
|
检查进一步执行所必需的分派条件。
|
以上的类、属性或者方法中,常用的也就是上面那几个,下面就逐个了解一下。
DispatchWorkItem,即派发工作项,可以将要执行的任务以闭包的方式封装到DispatchWorkItem对象中。
常用方法如下:
方法名称
|
描述
|
init(qos: DispatchQoS, flags: DispatchWorkItemFlags, block: () -> Void)
|
初始化方法,可直接带一个闭包,也可添加一些配置项再带闭包。
|
func perform()
|
在当前线程同步执行工作项任务。
|
func cancel()
|
取消工作项,异步。
|
func notify(queue: DispatchQueue, execute: DispatchWorkItem)
|
工作项任务结束后通知执行指定的工作项。
|
func notify(qos: DispatchQoS, flags: DispatchWorkItemFlags, queue: DispatchQueue, execute: () -> Void)
|
工作项任务结束后通知执行具有指定配置的闭包任务。
|
func wait()
|
阻塞当前线程,直到工作项任务结束。
|
代码示例如下:
func workItemDemo() {
let workItem1 = DispatchWorkItem {
print("workItem 1, thread: \(Thread.current)")
sleep(1)
let workItem2 = DispatchWorkItem(qos: .unspecified, flags: .inheritQoS) {
print("workItem 2, thread: \(Thread.current)")
sleep(1)
workItem2.notify(qos: .unspecified, flags: .inheritQoS, queue: DispatchQueue.global()) {
print("workItem 2 finished, thread: \(Thread.current)")
let workItem3 = DispatchWorkItem(qos: .unspecified, flags: .inheritQoS) {
print("workItem 3, thread: \(Thread.current)")
sleep(1)
workItem3.cancel()
let workItem4 = DispatchWorkItem(qos: .unspecified, flags: .inheritQoS) {
print("workItem 4, thread: \(Thread.current)")
sleep(1)
workItem4.notify(queue: DispatchQueue.main, execute: workItem1)
let workItem5 = DispatchWorkItem(qos: .unspecified, flags: .inheritQoS) {
print("workItem 5, thread: \(Thread.current)")
sleep(1)
workItem2.perform()
workItem3.perform()
workItem4.perform()
workItem5.perform()
执行结果:
workItem 2, thread: <NSThread: 0x600003f30bc0>{number = 1, name = main}
workItem 4, thread: <NSThread: 0x600003f30bc0>{number = 1, name = main}
workItem 2 finished, thread: <NSThread: 0x600003f75b40>{number = 3, name = (null)}
workItem 5, thread: <NSThread: 0x600003f30bc0>{number = 1, name = main}
workItem 1, thread: <NSThread: 0x600003f30bc0>{number = 1, name = main}
一个可以在应用程序的主线程或后台线程上连续或并发地管理任务的执行的对象。
open class DispatchQueue : DispatchObject {
DispatchQueue是一个FIFO队列,可以将任务以闭包或者DispatchWorkItem对象的形式提交给它。DispatchQueue会以串行或并行方式执行任务。提交给DispatchQueue的任务在系统管理的线程池中执行。
我们可以同步或异步地调度任务。当使用同步的方式调度一个任务时,后续的代码将停止执行,直到调度的任务执行结束。当使用异步的方式调度任务时,代码将继续执行。
切记在主队列上同步执行任务会导致死锁。
DispatchQueue有三种形式,具体看下表:
类型 | 创建方式 | 执行方式 | 描述 |
---|
主队列(main queue) | DispatchQueue.main | 串行(Serial) | 与主线程有关,加入到主队列的任务项都会在主线程中执行。 |
全局队列(global queue) | DispatchQueue.global() | 并行(Concurrent) | 在后台线程中执行任务,用于处理并发任务,具备开启多个线程的能力。 |
自定义队列(custom queue) | init(label: String, qos: DispatchQoS, attributes: DispatchQueue.Attributes, autoreleaseFrequency: DispatchQueue.AutoreleaseFrequency, target: DispatchQueue?) | 串行/并行 | 在后台线程中执行任务,默认为串行队列,即attributes不设值,当attributes为 .concurrent时,即为并行队列。串行队列只具备开启一个线程的能力,并行队列具备开启多个线程的能力。 |
三种创建DispatchQueue方式如下:
class var main: DispatchQueue { get }
class func global(qos: DispatchQoS.QoSClass = .default) -> DispatchQueue
* 创建一个派发队列。
* label:队列的唯一标识。
* qos :决定了系统安排任务执行的优先级。
* attributes : 执行队列的执行方式,串行还是并行。
* autoreleaseFrequency : 指示队列自动释放对象的频率的常量。
* target : 计划执行blocks的目标队列。如果希望系统提供适合当前对象的队列,请指定DISPATCH_TARGET_QUEUE_DEFAULT。
convenience init(label: String, qos: DispatchQoS = .unspecified, attributes: DispatchQueue.Attributes = [], autoreleaseFrequency: DispatchQueue.AutoreleaseFrequency = .inherit, target: DispatchQueue? = nil)
示例如下:
func dispatchQueueDemo() {
let mainQueue = DispatchQueue.main
let globalQueue = DispatchQueue.global()
let customConcurrentQueue = DispatchQueue(label: "com.queue.concurrent", qos: .unspecified, attributes: [.concurrent], autoreleaseFrequency: .inherit, target: nil)
let serialConcurrentQueue = DispatchQueue(label: "com.queue.serial", qos: .unspecified, attributes: [], autoreleaseFrequency: .inherit, target: nil)
print("mainQueue is \(mainQueue)")
print("globalQueue is \(globalQueue)")
print("customConcurrentQueue is \(customConcurrentQueue)")
print("serialConcurrentQueue is \(serialConcurrentQueue)")
输出结果:
mainQueue is <OS_dispatch_queue_main: com.apple.main-thread>
globalQueue is <OS_dispatch_queue_global: com.apple.root.default-qos>
customConcurrentQueue is <OS_dispatch_queue_concurrent: com.queue.concurrent>
serialConcurrentQueue is <OS_dispatch_queue_serial: com.queue.serial>
异步执行任务主要有以下这些方法:
func async(execute: DispatchWorkItem)
func asyncAfter(deadline: DispatchTime, execute: DispatchWorkItem)
func asyncAfter(deadline: DispatchTime, qos: DispatchQoS = .unspecified, flags: DispatchWorkItemFlags = [], execute work: @escaping @convention(block) () -> Void)
func asyncAfter(wallDeadline: DispatchWallTime, execute: DispatchWorkItem)
func asyncAfter(wallDeadline: DispatchWallTime, qos: DispatchQoS = .unspecified, flags: DispatchWorkItemFlags = [], execute work: @escaping @convention(block) () -> Void)
异步执行则强调调用的方法是异步方法,而并行或串行则强调队列的调度方式。
由4.1
节可知,队列如果细分则分为:
主队列
全局队列
自定义的串行队列
自定义的并行队列
下面看一下测试代码,分别用四种队列连续调用三次异步方法,并在闭包里面打印执行时间和线程。
func asyncDemo() {
DispatchQueue.main.async {
print("Main queue async block 1, \tdate : \(Date()), current thread : \(Thread.current)")
sleep(1)
DispatchQueue.main.async {
print("Main queue async block 2, \tdate : \(Date()), current thread : \(Thread.current)")
sleep(1)
DispatchQueue.main.async {
print("Main queue async block 3, \tdate : \(Date()), current thread : \(Thread.current)")
sleep(1)
DispatchQueue.global().async {
print("Global queue async block 1, \tdate : \(Date()), current thread : \(Thread.current)")
sleep(1)
DispatchQueue.global().async {
print("Global queue async block 2, \tdate : \(Date()), current thread : \(Thread.current)")
sleep(1)
DispatchQueue.global().async {
print("Global queue async block 3, \tdate : \(Date()), current thread : \(Thread.current)")
sleep(1)
let serialQueue = DispatchQueue(label: "com.queue.serial", qos: .unspecified, attributes: [], autoreleaseFrequency: .inherit, target: nil)
serialQueue.async {
print("serialQueue async block 1, \tdate : \(Date()), current thread : \(Thread.current)")
sleep(1)
serialQueue.async {
print("serialQueue async block 2, \tdate : \(Date()), current thread : \(Thread.current)")
sleep(1)
serialQueue.async {
print("serialQueue async block 3, \tdate : \(Date()), current thread : \(Thread.current)")
sleep(1)
let concurrentQueue = DispatchQueue(label: "com.queue.concurrent", qos: .unspecified, attributes: [.concurrent], autoreleaseFrequency: .inherit, target: nil)
concurrentQueue.async {
print("concurrentQueue async block 1, \tdate : \(Date()), current thread : \(Thread.current)")
sleep(1)
concurrentQueue.async {
print("concurrentQueue async block 2, \tdate : \(Date()), current thread : \(Thread.current)")
sleep(1)
concurrentQueue.async {
print("concurrentQueue async block 3, \tdate : \(Date()), current thread : \(Thread.current)")
sleep(1)
输出结果如下:
Global queue async block 3, date : 2020-11-19 05:11:10 +0000, current thread : <NSThread: 0x600002cff940>{number = 4, name = (null)}
Global queue async block 1, date : 2020-11-19 05:11:10 +0000, current thread : <NSThread: 0x600002c83380>{number = 7, name = (null)}
Global queue async block 2, date : 2020-11-19 05:11:10 +0000, current thread : <NSThread: 0x600002ce9000>{number = 6, name = (null)}
concurrentQueue async block 3, date : 2020-11-19 05:11:10 +0000, current thread : <NSThread: 0x600002c893c0>{number = 3, name = (null)}
concurrentQueue async block 2, date : 2020-11-19 05:11:10 +0000, current thread : <NSThread: 0x600002c8b8c0>{number = 9, name = (null)}
concurrentQueue async block 1, date : 2020-11-19 05:11:10 +0000, current thread : <NSThread: 0x600002cf29c0>{number = 8, name = (null)}
serialQueue async block 1, date : 2020-11-19 05:11:10 +0000, current thread : <NSThread: 0x600002c88ac0>{number = 5, name = (null)}
Main queue async block 1, date : 2020-11-19 05:11:10 +0000, current thread : <NSThread: 0x600002cc8900>{number = 1, name = main}
serialQueue async block 2, date : 2020-11-19 05:11:11 +0000, current thread : <NSThread: 0x600002c88ac0>{number = 5, name = (null)}
Main queue async block 2, date : 2020-11-19 05:11:11 +0000, current thread : <NSThread: 0x600002cc8900>{number = 1, name = main}
serialQueue async block 3, date : 2020-11-19 05:11:12 +0000, current thread : <NSThread: 0x600002c88ac0>{number = 5, name = (null)}
Main queue async block 3, date : 2020-11-19 05:11:12 +0000, current thread : <NSThread: 0x600002cc8900>{number = 1, name = main}
结果总结:
- 全局队列和自定义并行队列里面的任务是并发执行的,且为每个任务开启了一个线程去执行任务。
- 自定义串行队列里面的任务是依次执行的(符合FIFO原则),且该队列开启了一个线程去执行里面所有的任务。
- 主队列里面的任务是依次执行的(符合FIFO原则),且主队列里面的任务都在主线程中执行。
同步执行任务主要有以下这些方法:
func sync(execute workItem: DispatchWorkItem)
func sync(execute: () -> Void)
func sync<T>(execute work: () throws -> T) rethrows -> T
func sync<T>(flags: DispatchWorkItemFlags, execute work: () throws -> T) rethrows -> T
下面看一下测试代码,分别用全局队列
自定义的串行队列
自定义的并行队列
调动同步方法,并在闭包里面打印执行时间和线程。
func syncDemo() {
DispatchQueue.global().sync {
print("Global queue sync block 1, \tdate : \(Date()), current thread : \(Thread.current)")
sleep(1)
DispatchQueue.global().sync {
print("Global queue sync block 2, \tdate : \(Date()), current thread : \(Thread.current)")
sleep(1)
DispatchQueue.global().sync {
print("Global queue sync block 3, \tdate : \(Date()), current thread : \(Thread.current)")
sleep(1)
let serialQueue = DispatchQueue(label: "com.queue.serial", qos: .unspecified, attributes: [], autoreleaseFrequency: .inherit, target: nil)
serialQueue.sync {
print("serialQueue sync block 1, \tdate : \(Date()), current thread : \(Thread.current)")
sleep(1)
serialQueue.sync {
print("serialQueue sync block 2, \tdate : \(Date()), current thread : \(Thread.current)")
sleep(1)
serialQueue.sync {
print("serialQueue sync block 3, \tdate : \(Date()), current thread : \(Thread.current)")
sleep(1)
let concurrentQueue = DispatchQueue(label: "com.queue.concurrent", qos: .unspecified, attributes: [.concurrent], autoreleaseFrequency: .inherit, target: nil)
concurrentQueue.sync {
print("concurrentQueue sync block 1, \tdate : \(Date()), current thread : \(Thread.current)")
sleep(1)
concurrentQueue.sync {
print("concurrentQueue sync block 2, \tdate : \(Date()), current thread : \(Thread.current)")
sleep(1)
concurrentQueue.sync {
print("concurrentQueue sync block 3, \tdate : \(Date()), current thread : \(Thread.current)")
sleep(1)
输出结果如下:
Global queue sync block 1, date : 2020-11-19 05:31:13 +0000, current thread : <NSThread: 0x60000194ca00>{number = 1, name = main}
Global queue sync block 2, date : 2020-11-19 05:31:14 +0000, current thread : <NSThread: 0x60000194ca00>{number = 1, name = main}
Global queue sync block 3, date : 2020-11-19 05:31:15 +0000, current thread : <NSThread: 0x60000194ca00>{number = 1, name = main}
serialQueue sync block 1, date : 2020-11-19 05:31:16 +0000, current thread : <NSThread: 0x60000194ca00>{number = 1, name = main}
serialQueue sync block 2, date : 2020-11-19 05:31:17 +0000, current thread : <NSThread: 0x60000194ca00>{number = 1, name = main}
serialQueue sync block 3, date : 2020-11-19 05:31:18 +0000, current thread : <NSThread: 0x60000194ca00>{number = 1, name = main}
concurrentQueue sync block 1, date : 2020-11-19 05:31:19 +0000, current thread : <NSThread: 0x60000194ca00>{number = 1, name = main}
concurrentQueue sync block 2, date : 2020-11-19 05:31:20 +0000, current thread : <NSThread: 0x60000194ca00>{number = 1, name = main}
concurrentQueue sync block 3, date : 2020-11-19 05:31:21 +0000, current thread : <NSThread: 0x60000194ca00>{number = 1, name = main}
结果总结:
- 三种队列执行其任务的时候,没有开启新线程,而是直接在主线程执行任务。
- 同步函数执行的任务不分队列,按照调用顺序,依次执行。
- 主队列不能调用同步函数执行任务,否则死锁(示例代码中未写,详见
4.5 死锁分析
)。
主队列调用同步函数会死锁。
func mainQueueLockDemo() {
print("*** Start ***")
DispatchQueue.main.sync {
print("*** main sync function")
print("*** End ***")
上面这个方法中,运行结果只会打印*** Start ***
,然后程序就挂了。
原因分析:
凡是添加到主队列的任务,都会在主线程中执行。在将同步的sync block
添加到主队列的时候,主队列里面有一个任务mainQueueLockDemo()
正在执行,sync block
是同步的,所以需要等mainQueueLockDemo()
方法执行完才能开始执行,而sync block
不执行的话,mainQueueLockDemo()
方法是执行不完的,所以就存在相互等待对方执行完再执行的情况,即死锁。
看图示意:
下面将mainQueueLockDemo()
方法改一下,将主队列改成全局队列,即可避免死锁。
func mainQueueLockDemo() {
print("*** Start ***")
DispatchQueue.global().sync {
print("*** global sync function")
print("*** End ***")
输出结果:
*** Start ***
*** global sync function
*** End ***
死锁原理了解后,这个就很好理解了,mainQueueLockDemo()
是在主队列执行的,而sync block
是在全局队列执行的,两个不同的队列,将sync block
添加到全局队列后,在sync block
任务前没有任务执行,所以sync block
任务立即执行,此时,主队列的mainQueueLockDemo()
任务在等待状态,当全局队列中的sync block
任务结束后,主队列的mainQueueLockDemo()
任务继续执行,直到结束。
看图示意:
主队列调用同步函数会死锁,那么其他队列就不会死锁了吗?如果使用不当,同样是会死锁的,下面具体来看一下。
1. 自定义串行队列
func serialQueueLockDemo() {
let serialQueue = DispatchQueue(label: "serial")
serialQueue.sync {
print("sync execution, thread: \(Thread.current)")
serialQueue.sync {
print("sync execution, thread: \(Thread.current)")
serialQueue.async {
print("async execution, thread: \(Thread.current)")
serialQueue.sync {
print("sync execution, thread: \(Thread.current)")
serialQueue.sync {
print("sync execution, thread: \(Thread.current)")
serialQueue.async {
print("async execution, thread: \(Thread.current)")
serialQueue.async {
print("async execution, thread: \(Thread.current)")
serialQueue.async {
print("async execution, thread: \(Thread.current)")
- 自定义串行队列嵌套同步任务,死锁。
- 自定义串行队列嵌套异步任务,不会死锁。
2. 并行队列(全局队列、自定义并行队列)
func globalQueueLockDemo() {
DispatchQueue.global().async {
print("async execution thread: \(Thread.current)")
DispatchQueue.global().sync {
print("sync execution, thread: \(Thread.current)")
DispatchQueue.global().sync {
print("sync execution, thread: \(Thread.current)")
DispatchQueue.global().sync {
print("sync execution, thread: \(Thread.current)")
DispatchQueue.global().sync {
print("sync execution, thread: \(Thread.current)")
DispatchQueue.global().async {
print("async execution, thread: \(Thread.current)")
DispatchQueue.global().async {
print("async execution, thread: \(Thread.current)")
DispatchQueue.global().async {
print("async execution, thread: \(Thread.current)")
总结:
并行队列中不管是同步任务还是异步任务
再嵌套同步任务还是异步任务
都不会死锁。
DispatchGroup允许将同一队列或者不同队列的异步任务添加到组中,并且执行,当组内的所有任务都执行结束后,则执行组的回调函数通知程序以上异步任务都已经结束。
常用的方法如下:
public func notify(qos: DispatchQoS = .unspecified, flags: DispatchWorkItemFlags = [], queue: DispatchQueue, execute work: @escaping @convention(block) () -> Void)
public func notify(queue: DispatchQueue, work: DispatchWorkItem)
public func wait()
public func wait(timeout: DispatchTime) -> DispatchTimeoutResult
public func wait(wallTimeout timeout: DispatchWallTime) -> DispatchTimeoutResult
public func enter()
public func leave()
notify()
:组内所有任务执行完毕后,发送通知,可在当前队列监听,也可在主队列监听。
wait()
:阻塞当前线程,直到group所有任务执行完毕。
enter()
:显示的表示任务闭包加入了组中。
leave()
:显示的表示任务闭包执行结束,从组中移除。
下面创建一个group和一个自定义的并行队列,在并行队列中添加四个异步任务,然后group监听执行结束通知。
注:
- 不建议用全局的并行队列,保不齐哪里还用了。
- 在队列中添加异步任务,同步任务会依次在主线程中执行,这样就没有并发。
func groupDemo() {
let group = DispatchGroup()
let customQueue = DispatchQueue(label: "com.queue.concurrent", qos: .unspecified, attributes: [.concurrent], autoreleaseFrequency: .inherit, target: nil)
customQueue.async(group: group, qos: .unspecified, flags: .inheritQoS) {
print("async execution 1, thread: \(Thread.current)")
sleep(1)
customQueue.async(group: group, qos: .unspecified, flags: .inheritQoS) {
print("async execution 2, thread: \(Thread.current)")
sleep(1)
customQueue.async(group: group, qos: .unspecified, flags: .inheritQoS) {
print("async execution 3, thread: \(Thread.current)")
sleep(1)
customQueue.async(group: group, qos: .unspecified, flags: .inheritQoS) {
print("async execution 4, thread: \(Thread.current)")
sleep(1)
group.notify(qos: .unspecified, flags: .inheritQoS, queue: customQueue) {
print("All tasks finished, thread: \(Thread.current)")
输出结果如下:
async execution 1, thread: <NSThread: 0x6000021c3bc0>{number = 7, name = (null)}
async execution 3, thread: <NSThread: 0x6000021c1640>{number = 5, name = (null)}
async execution 4, thread: <NSThread: 0x6000021c2540>{number = 4, name = (null)}
async execution 2, thread: <NSThread: 0x6000021f1340>{number = 6, name = (null)}
All tasks finished, thread: <NSThread: 0x6000021c3bc0>{number = 7, name = (null)}
如果改成在主队列监听通知,代码如下:
group.notify(qos: .unspecified, flags: .inheritQoS, queue: DispatchQueue.main) {
print("All tasks finished, thread: \(Thread.current)")
输出结果如下:
async execution 2, thread: <NSThread: 0x600003e4dac0>{number = 7, name = (null)}
async execution 4, thread: <NSThread: 0x600003e08600>{number = 5, name = (null)}
async execution 1, thread: <NSThread: 0x600003e4e180>{number = 6, name = (null)}
async execution 3, thread: <NSThread: 0x600003e0c080>{number = 4, name = (null)}
All tasks finished, thread: <NSThread: 0x600003e40b40>{number = 1, name = main}
如果在主队列监听,那么监听函数的闭包即在主线程执行。
func groupDemo() {
let group = DispatchGroup()
let customQueue = DispatchQueue(label: "com.queue.concurrent", qos: .unspecified, attributes: [.concurrent], autoreleaseFrequency: .inherit, target: nil)
customQueue.async(group: group, qos: .unspecified, flags: .inheritQoS) {
print("async execution 1, thread: \(Thread.current)")
sleep(1)
customQueue.async(group: group, qos: .unspecified, flags: .inheritQoS) {
print("async execution 2, thread: \(Thread.current)")
sleep(1)
customQueue.async(group: group, qos: .unspecified, flags: .inheritQoS) {
print("async execution 3, thread: \(Thread.current)")
sleep(1)
customQueue.async(group: group, qos: .unspecified, flags: .inheritQoS) {
print("async execution 4, thread: \(Thread.current)")
sleep(1)
print("All tasks finished, thread: \(Thread.current)")
上面demo中,先把group.wait()
注释掉,输出结果中,“All tasks finished”这句话提前调用了,如下:
async execution 1, thread: <NSThread: 0x600000a6a780>{number = 8, name = (null)}
All tasks finished, thread: <NSThread: 0x600000a78900>{number = 1, name = main}
async execution 3, thread: <NSThread: 0x600000a3e0c0>{number = 7, name = (null)}
async execution 2, thread: <NSThread: 0x600000a34f40>{number = 5, name = (null)}
async execution 4, thread: <NSThread: 0x600000a3c300>{number = 4, name = (null)}
如果将group.wait()
注释取消,wait()会阻塞当前线程,直到group中的任务都执行结束了,看下面结果:
async execution 3, thread: <NSThread: 0x600002582180>{number = 6, name = (null)}
async execution 1, thread: <NSThread: 0x60000258eb80>{number = 5, name = (null)}
async execution 2, thread: <NSThread: 0x6000025def00>{number = 4, name = (null)}
async execution 4, thread: <NSThread: 0x6000025c4e00>{number = 7, name = (null)}
All tasks finished, thread: <NSThread: 0x6000025cc040>{number = 1, name = main}
func groupDemo() {
let group = DispatchGroup()
let customQueue = DispatchQueue(label: "com.queue.concurrent", qos: .unspecified, attributes: [.concurrent], autoreleaseFrequency: .inherit, target: nil)
group.enter()
customQueue.async {
print("async execution 1, thread: \(Thread.current)")
sleep(1)
group.leave()
group.enter()
customQueue.async {
print("async execution 2, thread: \(Thread.current)")
sleep(1)
group.leave()
group.enter()
customQueue.async {
print("async execution 3, thread: \(Thread.current)")
sleep(1)
group.leave()
group.enter()
customQueue.async {
print("async execution 4, thread: \(Thread.current)")
sleep(1)
group.leave()
let workItem = DispatchWorkItem {
print("All tasks finished, thread: \(Thread.current)")
group.notify(queue: DispatchQueue.main, work: workItem)
DispatchQoS调度优先级:应用在任务上的服务质量或执行优先级。可以用来修饰DispatchWorkItem、DispatchQueue。
DispatchQoS类型如下表:
类型 | 描述 |
---|
userInteractive | 与用户交互相关的任务,比如动画,事件处理,UI处理等。 |
userInitiated | 用户主动发起的任务,要比较重视。 |
default | 默认任务,正常处理即可。 |
utility | 用户没有主动关注的任务。 |
background | 不太重要的维护、清理等任务,有空能处理完就行 |
unspecified | 没有指定优先级,看情况处理了。 |
上述列表中,优先等级由上至下逐渐降低。
工作项的一组行为,例如它的服务质量类,以及是否创建一个障碍或产生一个新的分离线程。
其可选值有:
static let assignCurrentContext: DispatchWorkItemFlags
static let barrier: DispatchWorkItemFlags
static let detached: DispatchWorkItemFlags
static let enforceQoS: DispatchWorkItemFlags
static let inheritQoS: DispatchWorkItemFlags
static let noQoS: DispatchWorkItemFlags
上面众多项中,最常用的也就是barrier
,下面看一下它的用法。
如果一个工作项的qos属性设置为barrier,那么在这个工作项之后的任务会在这个工作项之前的任务执行结束后再执行。
说起来比较拗口,下面看代码:
func barrierDemo() {
let workItem1 = DispatchWorkItem(qos: .unspecified, flags: .inheritQoS) {
print("workItem 1, thread: \(Thread.current)")
sleep(1)
let workItem2 = DispatchWorkItem(qos: .unspecified, flags: .inheritQoS) {
print("workItem 2, thread: \(Thread.current)")
sleep(1)
let workItem3 = DispatchWorkItem(qos: .unspecified, flags: .inheritQoS) {
print("workItem 3, thread: \(Thread.current)")
sleep(1)
let workItem4 = DispatchWorkItem(qos: .unspecified, flags: .inheritQoS) {
print("workItem 4, thread: \(Thread.current)")
sleep(1)
let workItem5 = DispatchWorkItem(qos: .unspecified, flags: .inheritQoS) {
print("workItem 5, thread: \(Thread.current)")
sleep(1)
let customQueue = DispatchQueue(label: "com.queue.concurrent", qos: .unspecified, attributes: [.concurrent], autoreleaseFrequency: .inherit, target: nil)
customQueue.async(execute: workItem1)
customQueue.async(execute: workItem2)
customQueue.async(execute: workItem3)
customQueue.async(execute: workItem4)
customQueue.async(execute: workItem5)
上面创建了一并行队列,并异步执行了五个任务,输出结果如下:
workItem 1, thread: <NSThread: 0x60000051c140>{number = 5, name = (null)}
workItem 5, thread: <NSThread: 0x60000051c8c0>{number = 3, name = (null)}
workItem 2, thread: <NSThread: 0x6000005162c0>{number = 4, name = (null)}
workItem 4, thread: <NSThread: 0x600000519cc0>{number = 8, name = (null)}
workItem 3, thread: <NSThread: 0x600000566e80>{number = 7, name = (null)}
如果将workItem3
的初始化修改一下,如下:
let workItem3 = DispatchWorkItem(qos: .unspecified, flags: .barrier) {
print("workItem 3, thread: \(Thread.current)")
sleep(1)
那么workItem3
将起到屏障的作用,workItem1
和workItem2
在workItem3
之前执行,workItem4和workItem5
在workItem3
之后执行。看一下输出结果:
workItem 2, thread: <NSThread: 0x600001dccb00>{number = 2, name = (null)}
workItem 1, thread: <NSThread: 0x600001dcdcc0>{number = 4, name = (null)}
workItem 3, thread: <NSThread: 0x600001dcdcc0>{number = 4, name = (null)}
workItem 4, thread: <NSThread: 0x600001dcdcc0>{number = 4, name = (null)}
workItem 5, thread: <NSThread: 0x600001dccb00>{number = 2, name = (null)}
本文主要讲解了GCD的概念,DispatchQueue、DispatchGroup以及死锁等,希望不仅帮助自己,也能帮助他人更好的使用Swift GCD,如果想精通,还需在后续的开发中不断地摸索,同时也欢迎各位朋友就本文章做出指正。
如果觉得文章对你有用,不妨给个赞,关注一下,更多好用文章还在继续更新中。
本篇文章出自https://blog.csdn.net/guoyongming925的博客,如需转载,请标明出处。
这本书教你如何为你的iOS应用程序编写高性能和并发代码。
了解什么是并发,为什么你甚至想在你的应用程序中使用它? 了解Grand Central Dispatch,Apple对C的libdispatch的实现,也称为GCD,因为它是排队任务并行运行的最简单方法之一。 然后,当GCD没有完全削减它时,采取操作和操作队列; 您将学习如何进一步定制和重用您的并发工作。 然后,您将学习在开发并发应用程序时可能遇到的常见并发问题,例如Race Conditions,Deadlocks等。 最后,了解线程和线程清理程序以及各种与线程相关的概念以及这些概念如何与您在本书中积累的知识相关联。 您还将学习如何在出现问题时使用Thread Sanitizer来简化调试。
国庆长假,不想一行白鹭上青天,回家挤在在最中间。就把征战已久的古董pro挖出,硬生生升到了macOS Sierrra,跑起了 Xcode 8 ,写起了swift。
先来一波实用干货。
swift 闭包项目的实际应用,和objective-c 的 Block 类似。HttpTool 工具类import UIKitclass HttpTool: NSObject {
// 闭包的类型:
从
Swift3开始
GCD的API就发生了很大的变化,更加简洁,使用起来更方便。像我们经常开启一个异步线程处理事情然后切回主线程刷新UI操作,这里就变的非常简单了。 DispatchQueue.global().async {
// do async task
DispatchQueue.main.async {
// update UI
GCD(Grand Central Dispatch)是基于C语言开发的一套多线程开发机制,也是目前苹果官方推荐的多线程开发方法。相对于 NSThread 和 NSOperation,GCD抽象层次最高,使用起来也最简单,只是它基于C语言开发,并不像NSOperation是面向对象的开发,而是完全面向过程的。这种机制相比较于前面两种多线程开发方式最显著的优点就是它对于多核运算更加有效。
GCD......
之前遇到一个问题,一个请求需要在另一个请求获得的参数。这个时候最开始的办法是把第二个请求写在第一个请求的回调里,但是这样的话,两个请求就很紧密的耦合在一起了。这个时候可以使用信号量来使他们分离开来。
先看下相关的3个方法:
dispatch_semaphore_t dispatch_semaphore_create(long value):方法接收一个long类型的参数, 返回一个disp...
在iOS Swift中连接扫描枪的代码主要分为两个部分:Bluetooth连接和接收扫描数据。
首先,需要在应用中引入CoreBluetooth库。在ViewController中创建一个BLEManager类,并像下面这样定义其属性和方法:
```swift
class BLEManager: NSObject, CBCentralManagerDelegate, CBPeripheralDelegate {
var centralManager: CBCentralManager?
var peripheral: CBPeripheral?
var characteristic:CBCharacteristic?
override init() {
super.init()
centralManager = CBCentralManager(delegate: self, queue: nil)
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state == .poweredOn {
central.scanForPeripherals(withServices:nil, options: nil)
print("Scanning started")
} else {
print("Bluetooth not available.")
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
if (peripheral.name == "Your peripheral name") {
self.centralManager?.stopScan()
self.peripheral = peripheral
self.peripheral?.delegate = self
self.centralManager?.connect(self.peripheral!, options: nil)
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
if peripheral == self.peripheral {
peripheral.discoverServices(nil)
print("Connected to your peripheral")
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
for service in peripheral.services! {
peripheral.discoverCharacteristics(nil, for: service)
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
for characteristic in service.characteristics! {
if characteristic.uuid == CBUUID(string: "Your characteristic UUID") {
self.characteristic = characteristic
peripheral.setNotifyValue(true, for: characteristic)
print("Characteristic found")
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
if characteristic == self.characteristic {
if let data = characteristic.value {
let string = String(data: data, encoding: .utf8)!
print("Scanned barcode is: \(string)")
接着,在ViewController中初始化BLEManager并调用centralManager的方法:
```swift
var bleManager: BLEManager?
override func viewDidLoad() {
super.viewDidLoad()
bleManager = BLEManager()
最后,需要将扫描枪的UUID和特征UUID替换为自己的。这样,应用就能连接扫描枪并接收扫描数据了。
升级Xcode12.3报错(Building for iOS Simulator, but the linked and embedded framework ‘***‘ was built ...)
16735
Xcode12 building for iOS Simulator, but linking in dylib built for iOS, file for architecture arm64
Xcode12 building for iOS Simulator, but linking in dylib built for iOS, file for architecture arm64
zzzzzz9527:
Xcode12.5编译RN项目报错(Cannot initialize a parameter of type ‘NSArray<id<RCTBridgeModule>> *‘ with an...)
Daniel_Coder:
Xcode12.5编译RN项目报错(Cannot initialize a parameter of type ‘NSArray<id<RCTBridgeModule>> *‘ with an...)
七月星辰:
升级Xcode12.3报错(Building for iOS Simulator, but the linked and embedded framework ‘***‘ was built ...)
Daniel_Coder:
升级Xcode12.3报错(Building for iOS Simulator, but the linked and embedded framework ‘***‘ was built ...)
智域智联科技: