Swift 多线程

/ Mac / 没有评论 / 1400浏览

Swift 多线程

容易混淆的术语:同步 异步 串行 并发

sync和async用来控制是否要开启新的线程.队列的类型,决定了任务的执行方式(并发 串行). async只表示具有开启新线程的能力,但不一定开启新的线程.比如async传入主队列不会开启新的线程.主队列是在主线程执行.

以下代码输出结果是什么?为什么?

override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = UIColor.blue
        
        let queue = DispatchQueue.main
        queue.sync {
            print(1)
        }
  }

viewDidLoad方法本身就是主线程的一个任务.viewDidLoad这个任务是先添加进主线程的一个任务,需要先将viewDidLoad这个任务执行完,才能执行queue.sync任务.但queue.sync是后后添加的任务,需要等上一个任务viewDidLoad执行完才能执行,所以构成死锁.

override func viewDidLoad() {
  super.viewDidLoad()
  view.backgroundColor = UIColor.blue
  print(1111)
  let queue = DispatchQueue.main
  queue.async {
    print(22222)
  }
  print(3333333)
}
//打印结果
1111
3333333
22222

自定义并发队列

override func viewDidLoad() {
  super.viewDidLoad()
  view.backgroundColor = UIColor.blue
  //这是一个并发队列
  let serialQueue = DispatchQueue.init(label: "", qos: .default, attributes: [.concurrent], autoreleaseFrequency: .inherit, target: nil)
  print(1111,Thread.current)
  serialQueue.async {
    print(2222,Thread.current)
    serialQueue.sync {
      print(33333,Thread.current)
    }
    print(4444444444,Thread.current)
    serialQueue.sync {
      print(555555555,Thread.current)
    }
    print(666666666,Thread.current)
  }
  print(77777777,Thread.current)
}
//打印结果
//注意:22的打印可能介于11和77之间,因为`async`函数不要求立刻执行,什么时候执行不确定.有可能22执行结束优先于777
1111 <NSThread: 0x600000d0a2c0>{number = 1, name = main}
77777777 <NSThread: 0x600000d0a2c0>{number = 1, name = main}
2222 <NSThread: 0x600000d88440>{number = 7, name = (null)}
33333 <NSThread: 0x600000d88440>{number = 7, name = (null)}
4444444444 <NSThread: 0x600000d88440>{number = 7, name = (null)}
555555555 <NSThread: 0x600000d88440>{number = 7, name = (null)}
666666666 <NSThread: 0x600000d88440>{number = 7, name = (null)}

自定义串行队列

override func viewDidLoad() {
  super.viewDidLoad()
  view.backgroundColor = UIColor.blue
  //这是一个并发队列
  let serialQueue = DispatchQueue(label: "自定义串行队列")
  print(11111)
  serialQueue.async {
    print(22222)
    //往串行队列中添加同步(立刻执行的任务会造成死锁)
    serialQueue.sync {
      print(3333)
    }
    print(4444)
  }
  print(5555)
}
//打印结果
//理论上22222的打印可能介于111和555之间
11111
5555
22222
4444
3333

死锁产生条件

RunLoop和多线程相关问题

如下代码输出什么?为什么?

class HomeViewController: UIViewController {
  override func viewDidLoad() {
    super.viewDidLoad()
    let queue = DispatchQueue.global()
    queue.async {
      print(1)
      self.perform(#selector(self.test), with: nil, afterDelay: 0)
      print(2)
    }  
  }
  
  @objc func test() {
    print("test")
  }
}
//打印,没有看到test方法执行
1
2
override func viewDidLoad() {
  super.viewDidLoad()
  view.backgroundColor = UIColor.blue
  let queue = DispatchQueue.global()
  queue.async {
    print(111)
    self.perform(#selector(self.test), with: nil, afterDelay: 0.0)
    print(333)
    //在子线程中添加runloop
    let port = Port()
    //perform(#selector(self.test), with: nil, afterDelay: 0.0)
    //方法已经在子线程的runloop中添加了NSTimer.所以不
    //需要再添加 port,所以这句代码可以去掉
    //runloop中只要有 source timer observer runloop就可以
    //成功运行
    RunLoop.current.add(port, forMode: .default)
    //RunLoop.current.run()
    RunLoop.current.run(mode: .default, before: Date.distantFuture)
  }

}
//打印结果
111
333
2222

下面代码执行结果是什么?

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
  let thread = Thread.init {
    print(1)
  }

  thread.start()
  self.perform(#selector(self.test), on: thread, with: nil, waitUntilDone: true)
}

@objc func test() {
  print(2)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
  let thread = Thread.init {
    print(1)
    //在runloop中添加source timer observer
    RunLoop.current.add(Port(), forMode: .default)
    //启动runloop
    RunLoop.current.run()
  }

  thread.start()
  self.perform(#selector(self.test), on: thread, with: nil, waitUntilDone: true)
}

@objc func test() {
  print(2)
}

队列组的使用

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
  //创建队列组
  let group = DispatchGroup()
  //创建并发队列
  let queue = DispatchQueue.global()
  queue.async(group: group, execute: {
    for _ in 0...10{
      print(1,"任务1",Thread.current)
    }
  })
  queue.async(group: group, execute: {
    for _ in 0...10{
      print(2,"任务2",Thread.current)
    }
  })
  group.notify(queue: queue) {
    DispatchQueue.main.async {
      for _ in 0...10{
        print(3,"任务3",Thread.current)
      }
    }
  }
}
group.notify(queue: DispatchQueue.main) {
  for _ in 0...10{
    print(3,"任务3",Thread.current)
  }
}
//或者
group.notify(queue: queue) {
  DispatchQueue.main.sync {
    for _ in 0...10{
      print(3,"任务3",Thread.current)
    }

  }
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
  //创建队列组
  let group = DispatchGroup()
  //创建并发队列
  let queue = DispatchQueue.global()
  
  queue.async(group: group, execute: {
    for _ in 0...5{
      print(1,"任务1",Thread.current)
    }
  })
  queue.async(group: group, execute: {
    for _ in 0...5{
      print(2,"任务2",Thread.current)
    }
  })
  group.notify(queue: queue) {
    for _ in 0...5{
      print(3,"任务3",Thread.current)
    }
  }
  group.notify(queue: queue) {
    for _ in 0...5{
      print(4,"任务4",Thread.current)
    }
  }
}

2