iOS 线程

Operation

队列 说明 执行方式
main 主线程队列 只能在main thread上执行
new 自定义线程队列 子线程执行
currentQueue 根据当先线程创建的队列 如果当前线程是主线程,那么队列里的任务只能在main thread执行,如果是子线程,那么就会在人物就在子线程执行线程

OperationQueue 方便控制并发数量(maxConcurrentOperationCount)、配置服务质量(qualityOfService),撤销排队的任务(cancelAllOperations),暂停或唤醒(isSuspended),等待等. 当并发数为1时,队列的任务会串行。

Operation 同样支持配置qos服务质量,队列优先级,线程优先级,启动,暂停,撤销,结束任务,依赖,Operation直接start会在当前线程执行

CGD

串行队列 并行队列
DispatchQueue.main DispatchQueue.global(qos: DispatchQoS.QoSClass.default)
DispatchQueue(label: "Queue") DispatchQueue(label: "label", attributes: DispatchQueue.Attributes.concurrent) concurrent是同时的意思
sync async
阻塞当前线程执行另外一个任务 继续执行,不等待提交的任务执行结束继

GCD在Group和延after操作中有类似OperationQueue的DispatchQoS

相比operation支持同步执行,但没有设置队列优先级、线程优先级、启动、暂停、撤销、结束等操作

死锁

在属于串行队列的线程上sync向这个队列提交任务,会死锁

// thread a created by serial queue A
dispatch_sync(A) ^ {
  // work 1
}
// work 2
  • 以上情况,work 2需要等待work 1结束,可是work 1放到串行的队列A中, work 2没结束,work 1永远无法执行
  • 如果A为并行队列,则work 1可能会被提交到另外一个线程执行
  • 如果为dispatch_async 则会继续执行work 2, work 1会稍后执行
  • 如果线程a不是队列A创建的,者A会另外创建一个队列如a', 并执行work 1,然后返回继续执行work 2

延迟

DispatchQueue.global().asyncAfter(deadline: DispatchTime.now() + DispatchTimeInterval.seconds(3)) {
    print(Thread.current.name)
}

循环

并行,不限于主线程,线程会复用

DispatchQueue.concurrentPerform(iterations: 10) { (index) in
    print(index,Thread.current)
}

挂起与唤醒

let queue = DispatchQueue(label: "new thread")
queue.suspend()
queue.async { print(queue.label) }
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + DispatchTimeInterval.seconds(3)) {
    queue.resume()
}

信号量

用于控制并发

let semaphoreSignal = DispatchSemaphore(value: 4)
for index in 1...20 {
    DispatchQueue.global().asyncAfter(deadline: DispatchTime.now() + DispatchTimeInterval.milliseconds(10)) {
        // semaphoreSignal.wait() // 2
        print(index, Thread.current)
        semaphoreSignal.signal()
    }
    semaphoreSignal.wait() // 1
    print("for loop", index)
}
print("for loop end")

异步执行先执行wait, semaphore-1, 而block中signal还没来得及执行,当semaphore减到0时则会阻塞for循环所在线程,直到下一次signal执行
semaphore初始值控制并发数量,当为1时下面的任务就变成串行的
如果wait写在“2”处,则是一次性向global queue提交所有任务,阻塞的是子线程,但并发就不一定是4个了

let group = DispatchGroup()
// 向特定的队列添加任务到组
DispatchQueue(label: "queue").async(group: group) {
    print("some work 1", Thread.current)
}
// 手动告诉任务的起始和终止
group.enter()
OperationQueue().addOperation {
    print("some work 2", Thread.current)
    group.leave()
}
// 组任务完成后的操作
group.notify(queue: DispatchQueue.global()) {
    print("finished", Thread.current)
}

Thread

基本用法

Thread.detachNewThread {print("way 1", Thread.current)} // 直接执行

let thread2 = Thread.init {
    for index in 0..<100 {
        print("way 2", index, Thread.current)
        Thread.sleep(until: Date(timeIntervalSinceNow: 1)) // 延迟
        if index > 10 {Thread.exit()} // 退出
    }
}
thread2.start() // 启动

class Obj { @objc func thread3Selector() {print("way 3", Thread.current)}}  // selector形式
let thread3 = Thread.init(target: Obj(), selector: #selector(Obj.thread3Selector), object: nil)
thread3.start()

状态

  • 就绪<-->运行,cpu调度
  • 阻塞<-->运行,sleep控制
  • 退出:任务结束自动退出,exit强制退出, cancel按需退出

NSCondition

var conditionA = NSCondition()
var conditionB = NSCondition()
let thread = Thread.init {
    for i in 0...12 {
        if i % 3 == 0 {
            conditionB.signal()
            conditionA.lock()
            conditionA.wait()
            conditionA.unlock()
        }
        print(Thread.current, i)
    }
    print(Thread.current, "fihished")
}
Thread.init {
    for i in 0...12 {
        if i % 3 == 0 {
            if thread.isExecuting {
                conditionA.signal()
            } else {
                thread.start()
            }
            conditionB.lock()
            conditionB.wait()
            conditionB.unlock()
        }
        print(Thread.current, i)
    }
    print(Thread.current, "fihished")
}.start()

其他

GCD和Operation不可以创建和释放线程,不可以通过它们直接控制任务放到哪一个线程上执行,创建的线程不一定马上释放,可能会被复用

不要过多的diapatch_asyc(Queue.new)或者queue.maxConcurrentOperationCount = largeNumber, 过多的线程调度容易造成额外的负担

异步改同步

方案一,信号量

func sycnfunction() -> [Int] {
    let semaphoreSignal = DispatchSemaphore(value: 0)
    var numbers: [Int] = []
    for index in 0..<9 {
        DispatchQueue.global().asyncAfter(deadline: DispatchTime.now() + DispatchTimeInterval.milliseconds((index % 3) * 10 + 100)) {
            numbers.append(index)
            print(index, Thread.current)
            semaphoreSignal.signal()
        }
        print("for loop", index)
    }
    // 阻塞当前function, 等待前面的
    for _ in 0..<9 {
        semaphoreSignal.wait()
    }
    return numbers
}
print("start")
print("end", sycnfunction())

第一个for用于一次性提交所有的任务到队列中,紧接着wait同等个数,此时当前函数现车个被阻塞,知道所有的异步任务执行完signal,函数开始返回

注意,异步函数中numbers并非线程安全,这里简单把两个任务时间乘以十倍隔开防止冲突(index % 3) * 10

results matching ""

    No results matching ""