多线程

优质
小牛编辑
140浏览
2023-12-01

多线程

Swift多线程编程方案

  • Thread
  • Cocoa Operation (OperationOperationQueue)
  • Grand Central Dispath (GCD)

1. Thread在三种多线程技术中是最轻量级的, 但需要自己管理线程的生命周期和线程同步. 线程同步对数据的加锁会有一定的系统开销.

  • detachNewThread(_ block: @escaping () -> Void)
  • detachNewThreadSelector(_ selector: Selector, to Target target: Any, with argument: Any?)

e.g.

for i in 0...10 {
    Thread.detachNewThread {
        print("\(i) \(Thread.current)")
    }
}

输出结果:

8 <NSThread: 0x6000000f8e40>{number = 12, name = (null)}
10 <NSThread: 0x6000000f0240>{number = 17, name = (null)}
7 <NSThread: 0x6000000cc0c0>{number = 10, name = (null)}
1 <NSThread: 0x6000000c0180>{number = 14, name = (null)}
6 <NSThread: 0x6000000efe80>{number = 9, name = (null)}
4 <NSThread: 0x6000000efdc0>{number = 11, name = (null)}
5 <NSThread: 0x6000000c8580>{number = 15, name = (null)}
9 <NSThread: 0x6000000cc080>{number = 8, name = (null)}
0 <NSThread: 0x6000000fd300>{number = 7, name = (null)}
2 <NSThread: 0x6000000cc5c0>{number = 13, name = (null)}
3 <NSThread: 0x6000000f0780>{number = 16, name = (null)}

e.g.

class ObjectForThread {
    func threadTest() -> Void {
        let thread = Thread(target: self, selector: #selector(threadWorker), object: nil)
        thread.start()
        print("threadTest")
    }
    @objc func threadWorker() -> Void {
        print("threadWorker Run")
    }
}

let obj = ObjectForThread()
obj.threadTest()

输出结果:

threadTest
threadWorker Run

2. OperationOperationQueue

Operation

  • 面向对象 (OperationBlockOperation)
  • Operation+ OperationQueue
  • 取消、依赖、任务优先级、复杂逻辑、保存业务状态、子类化

Operation的四种状态 :

  • isReady
  • isExecuting
  • isFinished
  • isCancelled

OperationQueue

  • OperationQueue队列里可以加入很多个Operation, 可以把OperationQueue看做一个线程池, 可以往线程池中添加操作(Operation)到队列中
  • 底层使用GCD
  • maxConcurrentOperationCount可以设置最大并发数
  • defaultMaxConcurrentOperationCount根据当前系统条件动态确定的最大并发数
  • 可以取消所有Operation, 但是当前正在执行的不会取消
  • 所有Operation执行完毕后退出销毁

e.g. BlockOperation

class ObjectForThread {
    func threadTest() -> Void {
        let operation = BlockOperation { [weak self] in
            self?.threadWorker()
        }
        let queue = OperationQueue()
        queue.addOperation(operation)
        print("threadTest")
    }
}

let obj = ObjectForThread()
obj.threadTest()

e.g. 自定义的Operation

class ObjectForThread {
    func threadTest() -> Void {
        let operation = MyOperation()
        operation.completionBlock = {() -> Void in
            print("完成回调")
        }
        let queue = OperationQueue()
        queue.addOperation(operation)
        print("threadTest")
    }
}
class MyOperation: Operation {
    override func main() {
        sleep(1)
        print("MyOperation")
    }
}

let obj = ObjectForThread()
obj.threadTest()

3. GCD

GCD特点

  • 任务+队列
  • 易用
  • 效率
  • 性能

GCD - 队列

  • 主队列: 任务在主线程执行
  • 并行队列: 任务会以先进先出的顺序入列和出列, 但是因为多个任务可以并行执行, 所以完成顺序是不一定的.
  • 串行队列: 任务会以先进先出的顺序入列和出列, 但是同一时刻只会执行一个任务

GCD - 队列API

  • Dispatch.main
  • Dispatch.global
  • DispatchQueue(label:,qos:,attributes:,autoreleaseFrequency:,target:)
  • queue.label
  • setTarget(queue:DispatchQueue)

GCD 队列.png

  • 最终的目标队列都是主队列和全局队列
  • 如果把一个并行队列的目标队列都设置为同一个串行队列, 那么这多个队列连同目标队列里的任务都将串行执行
  • 如果设置目标队列成环了, 结果是不可预期的
  • 如果在一个队列正在执行任务的时候更换目标队列, 结果也是不可预期的

e.g.

let queue = DispatchQueue(label: "myQueue", qos: .default, attributes: .concurrent, autoreleaseFrequency: .inherit, target: nil)
queue.async {
    sleep(3)
    print("queue")
}
print("end")

e.g.

let queue = DispatchQueue(label: "myQueue", qos: .default, attributes: .concurrent, autoreleaseFrequency: .inherit, target: nil)
queue.asyncAfter(deadline: DispatchTime.now() + 10) {
    print("in asyncAfter")
}
print("end")

DispatchTime 系统时钟 DispatchWallTime生活时间

GCD 高级特性- DispatchGroup

e.g. 阻塞当前线程

let group = DispatchGroup()
let queue = DispatchQueue(label: "test.queue")

group.enter()
queue.async {
    sleep(3)
    print("操作 1")
    group.leave()
}

group.enter()
queue.async {
    sleep(3)
    print("操作 2")
    group.leave()
}

print("操作1 操作2 安排完成")

group.wait()
print("操作1 操作2 全部执行完毕")

e.g. 非阻塞方式:

let group = DispatchGroup()
let queue = DispatchQueue(label: "test.queue")

group.enter()
queue.async {
    sleep(3)
    print("操作 1")
    group.leave()
}

group.enter()
queue.async {
    sleep(3)
    print("操作 2")
    group.leave()
}

print("操作1 操作2 安排完成")

group.notify(queue: queue) {
    print("操作1 操作2 全部执行完毕")
}
print("非阻塞")

GCD 高级特性- DispatchSource

  • 简单来说, dispatch source是一个监听某些类型事件的对象. 当这些事件方法时, 它自动将一个task放入一个dispatch queue的执行历程中.

e.g. DispatchSource- Timer

var seconds = 10
let timer: DispatchSourceTimer = DispatchSource.makeTimerSource(flags: .strict, queue: .global())
timer.schedule(deadline: .now(), repeating: 1.0)
timer.setEventHandler {
    seconds -= 1
    if seconds < 0 {
        timer.cancel()
    }
    else {
        print(seconds)
    }
}
timer.resume()