Swift

Swift006-多线程

2019-07-19  本文已影响0人  DDY

Swift006-多线程

相关概念

例如主线程串行队列同步执行任务引起死锁

DispatchQueue.main.sync {
    print("死锁了不执行")
}

自定义串行队列同步任务 嵌套 该自定义串行队列同步任务,产生死锁

let serialQueue = DispatchQueue(label: "com.ddy.serialQueue")
serialQueue.sync {
    print("执行了1")
    serialQueue.sync {
        print("死锁了不执行")
    }
}

自定义串行队列异步任务 嵌套 该自定义串行队列同步任务, 产生死锁

let serialQueue = DispatchQueue(label: "com.ddy.serialQueue")
serialQueue.async {
    print("执行了1")
    serialQueue.sync {
        print("死锁了不执行")
    }
}
print("执行了3")

总结:遇到串行同步要小心

  1. 破坏“互斥”条件:就是在系统里取消互斥。若资源不被一个进程独占使用,那么死锁是肯定不会发生的。但一般“互斥”条件是无法破坏的。因此,在死锁预防里主要是破坏其他三个必要条件,而不去涉及破坏“互斥”条件。
  2. 破坏“请求和保持”条件:在系统中不允许进程在已获得某种资源的情况下,申请其他资源。即要想出一个办法,阻止进程在持有资源的同时申请其他资源。
    方法:要求每个进程提出新的资源申请前,释放它所占有的资源。这样,一个进程在需要资源S时,须先把它先前占有的资源R释放掉,然后才能提出对S的申请,即使它可能很快又要用到资源R。
  3. 破坏“不可抢占”条件:允许对资源实行抢夺。
    方法一:如果占有某些资源的一个进程进行进一步资源请求被拒绝,则该进程必须释放它最初占有的资源,如果有必要,可再次请求这些资源和另外的资源。
    方法二:如果一个进程请求当前被另一个进程占有的一个资源,则操作系统可以抢占另一个进程,要求它释放资源。只有在任意两个进程的优先级都不相同的条件下,该方法才能预防死锁。
  4. 破坏“循环等待”条件:将系统中的所有资源统一编号,进程可在任何时刻提出资源申请,但所有申请必须按照资源的编号顺序(升序)提出。这样做就能保证系统不出现死锁。
    方法:利用银行家算法避免死锁。

死锁参考

几种多线程技术比较

GCD抽象层次最高,使用也简单,因此,苹果也推荐使用GCD

GCD

1.主线程串行队列(main queue):提交至Main queue的任务会在主线程中执行,Main queue 可以通过DispatchQueue.main来获取,主队列一定伴随主线程,但主线程不一定伴随主队列。
2.全局并发队列(Global queue):全局并发队列由整个进程共享,有Qos优先级别。Global queue 可以通过调用DispatchQueue.global()函数来获取(可以设置优先级)
3.自定义队列(Custom queue): 可以为串行,也可以为并发。Custom queue 可以通过DispatchQueue(label: String)和DispatchQueue(label: String, attributes: DispatchQueue.Attributes.concurrent)来获取;
4.队列组 (Group queue):将多线程进行分组,最大的好处是可获知所有线程的完成情况。
Group queue 可以通过调用dispatch_group_create()来创建,通过dispatch_group_notify 可以直接监听组里所有线程完成情况。

6 自定义并发队列执行同步任务(顺序执行)

```
let concurrentQ = DispatchQueue(label: "concurrentQueue1", attributes: .concurrent)
print("执行了 1")
concurrentQ.sync {
    print("执行了 2")
}
concurrentQ.sync {
    print("执行了 3")
}
print("执行了 4")
```

7 自定义并发队列同步任务 嵌套 该自定义并发队列同步任务 (顺序执行 不会死锁)

```
let concurrentQ = DispatchQueue(label: "concurrentQueue1", attributes: .concurrent)
    print("执行了 1")
    concurrentQ.sync {
        print("执行了 2")
        concurrentQ.sync {
            print("执行了 3")
        }
    }
print("执行了 4")
```

8 自定义并发队列执行异步任务(2,3不确定顺序)

```
let concurrentQ = DispatchQueue(label: "concurrentQueue1", attributes: .concurrent)
print("执行了 1")
concurrentQ.async {
    print("执行了 2")
}
concurrentQ.async {
    print("执行了 3")
}
print("执行了 4")
```

队列便利构造器

- label: 队列的唯一标识符(用于调试)
- qos: 队列的优先级(.userInteractive .userInitiated .default .utility .background .unspecified)
    - .userInteractive:用户交互相关,为了好的用户体验,任务需要立马执行。使用该优先级用于UI更新,事件处理和小工作量任务,在主线程执行。
    - .userInitiated:优先级等同于DISPATCH_QUEUE_PRIORITY_HIGH,需要立刻的结果
    - .default:默认优先级,优先级等同于DISPATCH_QUEUE_PRIORITY_DEFAULT,建议大多数情况下使用默认优先级
    - .utility:优先级等同于DISPATCH_QUEUE_PRIORITY_LOW,可以执行很长时间,再通知用户结果。比如:下载一个大文件,网络,计算
    - .background:最低优先级,等同于DISPATCH_QUEUE_PRIORITY_BACKGROUND. 用户不可见,比如:在后台存储大量数据
    - .unspecified:未定义
- attributes: 队列属性(attributes是一个结构体并遵守OptionSet协议,所以传入的参数可以为[.option1, .option2])
    - .concurrent并发队列,
    - .initiallyInactive表明队列需要手动开启。不填写时默认队列串行、自动执行
- autoreleaseFrequency:自动释放频率,有些列队会在执行完任务之后自动释放,有些是不会自动释放的,需要手动释放。官方文档是说当设为.workItem时,所有异步任务提交的代码块会被封装成独立的任务,在同步执行的队列则不受影响。
- target:目标队列

```
// 队列的便利构造函数(便利构造器)
public convenience init(label: String, qos: DispatchQoS = .unspecified, attributes: DispatchQueue.Attributes = [], autoreleaseFrequency: DispatchQueue.AutoreleaseFrequency = .inherit, target: DispatchQueue? = nil)
// 优先级顺序:userInteractive> userInitiated> default> utility> background> unspecified

let label = "com.ddy.concurrentQueue"
let qos = DispatchQoS.default
let attributes = DispatchQueue.Attributes.concurrent
let autoreleaseFrequnecy = DispatchQueue.AutoreleaseFrequency.never
let queue = DispatchQueue(label: label, qos: qos, attributes: attributes, autoreleaseFrequency: autoreleaseFrequnecy, target: nil)
```

等待任务结束

```
let concurrentQ = DispatchQueue(label: "concurrentQueue1", attributes: .concurrent)
// 可以在初始化的时候指定更多的参数
let workItem = DispatchWorkItem(qos: .default, flags: .barrier) {
    sleep(5)
    print("done")
}
concurrentQ.async(execute: workItem)
print("before waiting")
workItem.wait()
print("after waiting")
// before waiting
// done
// after waiting
```

GCD一些常用函数

参考 Swift4 - GCD的使用
参考 Swift4.0 - GCD
参考 多线程之GCD
参考 从使用场景了解GCD新API

上一篇 下一篇

猜你喜欢

热点阅读