GCD多线程基本使用

编程入门 行业动态 更新时间:2024-10-26 08:29:55

GCD<a href=https://www.elefans.com/category/jswz/34/1767532.html style=多线程基本使用"/>

GCD多线程基本使用

Grand Central Dispatch简称GCD,苹果官方推荐给开发者使用的首选多线程解决方案。

 实际应用

因为Alamofire已经实现了异步请求的功能,所以没法实践,这个界面当时我在设计的时候(T.T因为做的不好看被一起开发的室友吐槽然后改掉了一部分)是直接将数据存储在沙盒目录下的test.plist文件里面,所以可以将他来变为异步请求。

以下是具体实现:

当model数据为空时,调用initData方法异步请求文件里的数据,不影响UI的刷新

    override func viewDidLoad() {super.viewDidLoad()if(bodydata.count==0){initData()}configUI()configNavbar()}

 initData的实现,首先定义了一个并行队列,队列添加异步任务请求数据,请求结束之后切换回主线程刷新UI(因为UI刷新任务都必须放在主线程,不然会报错)。

    func initData(){let Queue = DispatchQueue(label: "task",attributes: .concurrent)Queue.async {if(plistdata?.count == nil){let array:NSMutableArray = NSMutableArray()for item in origindata{let dictionary:NSMutableDictionary = [ : ]let center = item.centerText as NSStringdictionary.setValue(center, forKey: "centerText")array.add(dictionary)}array.write(toFile: filePath, atomically: false)bodydata = origindata}else{for item in plistdata!{let data = item as! NSDictionarylet center = data.value(forKey: "centerText") as! Stringlet sss = EditModel(centerText: center)if(bodydata.count == 5){break}else{bodydata.append(sss)}}}//切换到主线程刷新UIDispatchQueue.main.async {self.tableview.reloadData()}}}

基础认识

首先是队列的调度方式:并行和串行

并行:在本文中指并行队列,多个任务放在并行队列里执行,可以同时运行

串行:在本文中指串行队列,多个任务放在串行队列里执行,只能按顺序依次运行,前一个运行完成,下一个才能开始运行;前一个没运行完,后一个只能排队等着。以此类推,直到所有任务都运行完成。

                                                   并行

               

                                                   并发

任务的执行方式:同步和异步

同步:同步执行任务,在一个线程当中必须按顺序执行,执行结束的顺序也是固定的,而且同步任务会阻塞当前线程,直到同步任务结束才会结束阻塞,同步任务会经常造成线程的循环等待而导致死锁,慎用。

异步:异步执行任务,也是按顺序执行多项任务,但是是放在多个线程里同时运行,线程当中各个任务的开始执行时间和任务结束时间不固定,总耗时大约是耗时最长的那项任务所消耗的时间。

调度队列的种类:主队列,全局队列,自定义串行队列,自定义并行队列。

主队列(Main queue,串行队列):UI刷新的相关操作必须放在主队列

let mainQueue = DispatchQueue.main

全局队列(Global queue,并行队列):运行在后台线程,是系统内共享的全局队列,是一种并行队列(Concurrent),用于处理并发任务。因为是系统内共享,不单单属于这一个app,所以栅栏函数在全局队列中无效,为了避免堵塞其他程序的任务。

    1,全局队列没有名字,但是并发队列有名字。有名字可以便于查看系统日志

    2,全局队列是所有应用程序共享的。

    3,在mrc的时候,全局队列不用手动释放,但是并发队列需要。

let globalQueue = DispatchQueue.global()

自定义串行/并行队列(Custom queue):同样运行在后台。

//串行队列,label后为队列名字
let serialQueue = DispatchQueue(label: "fmy")//并行队列
let concurrentQueue = DispatchQueue(label: "fmy", attributes: .concurrent)

线程调度的优先级(Qos)

  • userInteractive: 与用户交互相关的任务,要最重视,优先处理,保证界面最流畅
  • userInitiated: 用户主动发起的任务,要比较重视
  • default: 默认任务,正常处理即可
  • utility: 用户没有主动关注的任务
  • background: 不太重要的维护、清理等任务,有空能处理完就行
  • unspecified: 别说身份了,连身份证都没有,能处理就处理,不能处理也无所谓的

优先级低的任务要等优先级高的执行完,即使是并行队列。

基础使用

//定义2个调度任务,打印当前线程数据
let item1 = DispatchWorkItem {for i in 0...4{print("item1 -> \(i)  thread: \(Thread.current)")}
}let item2 = DispatchWorkItem {for i in 0...4{print("item2 -> \(i)  thread: \(Thread.current)")}
}
//主队列追加异步任务,按顺序打印
let mainQueue = DispatchQueue.main
mainQueue.async(execute: item1)
mainQueue.async(execute: item2)//全局队列追加异步任务,随机打印
let globalQueue = DispatchQueue.global()
globalQueue.async(execute: item1)
globalQueue.async(execute: item2)//自定义串行队列追加异步任务,按顺序打印
let serialQueue = DispatchQueue(label: "serial")
serialQueue.async(execute: item1)
serialQueue.async(execute: item2)//自定义并行队列追加异步任务,随机打印
let concurrentQueue = DispatchQueue(label: "concurrent", attributes: .concurrent)
concurrentQueue.async(execute: item1)
concurrentQueue.async(execute: item2)

//主队列追加同步任务,会引起死锁
let mainQueue = DispatchQueue.main
mainQueue.sync(execute: item1)
mainQueue.sync(execute: item2)//全局队列追加同步任务,按顺序打印
let globalQueue = DispatchQueue.global()
globalQueue.sync(execute: item1)
globalQueue.sync(execute: item2)//自定义串行队列追加同步任务,按顺序打印
let serialQueue = DispatchQueue(label: "serial")
serialQueue.sync(execute: item1)
serialQueue.sync(execute: item2)//自定义并行队列追加同步任务,按顺序打印
let concurrentQueue = DispatchQueue(label: "concurrent", attributes: .concurrent)
concurrentQueue.sync(execute: item1)
concurrentQueue.sync(execute: item2)

死锁情况

1.主队列加入同步任务

2.串行队列当中的同步任务或者异步任务当中又嵌套了一个同步任务

原因分析:假设正在执行的任务是A任务(不管同步异步),A任务当中加入一个同步任务B(B任务属于A任务的一部分),要想执行完A任务,必须先执行B任务(因为同步任务阻塞线程),而调度队列又属于串行队列,A排在B前边,所以必须等任务A执行完才能执行任务B,这样就造成了循环等待,形成死锁。

//主队列添加同步任务
let mainQueue = DispatchQueue.main
mainQueue.sync(execute: item1)//同步任务
//自定义的串行队列
let serialQueue = DispatchQueue(label: "serial")
//死锁
serialQueue.sync {print("同步执行  thread: \(Thread.current)")serialQueue.sync {print("同步执行  thread: \(Thread.current)")}
}
//死锁
serialQueue.async {print("异步执行  thread: \(Thread.current)")serialQueue.sync {print("同步执行  thread: \(Thread.current)")}
}

3.不过自定义串行队列只加入同步任务不会导致死锁。煮个栗子:假如现在主线程在执行任务A(A任务在主队列当中),而串行队列加入了一个同步任务B,不管是什么队列加入同步任务,这个任务都会放到主线程去执行(分析见下文),所以这个时候,要想执行任务A,必须先执行任务B,而这个时候任务B可不可以执行呢?答案是可以,因为任务B在自定义的串行队列里面,而任务A在其他队列里面,这个时候任务B并没有被A给阻塞啊,所以是可以运行的,不会死锁。(所以说死锁针对的是队列,不是线程)

其他队列的同步任务也会放到主线程执行:

print("=> 开始执行")let mainQueue = DispatchQueue.main
mainQueue.async(execute: item1)//异步任务print("=> 执行完毕1")let globalQueue = DispatchQueue.global()
globalQueue.sync(execute: item2)//同步任务运行结果:
=> 开始执行
=> 执行完毕1
item2 -> 0  thread: <NSThread: 0x7fbf2cc0e7e0>{number = 1, name = main}
item2 -> 1  thread: <NSThread: 0x7fbf2cc0e7e0>{number = 1, name = main}
item2 -> 2  thread: <NSThread: 0x7fbf2cc0e7e0>{number = 1, name = main}
item2 -> 3  thread: <NSThread: 0x7fbf2cc0e7e0>{number = 1, name = main}
item2 -> 4  thread: <NSThread: 0x7fbf2cc0e7e0>{number = 1, name = main}
=> 执行完毕2
item3 -> 0  thread: <NSThread: 0x7fbf2cc0e7e0>{number = 1, name = main}
item3 -> 1  thread: <NSThread: 0x7fbf2cc0e7e0>{number = 1, name = main}
item3 -> 2  thread: <NSThread: 0x7fbf2cc0e7e0>{number = 1, name = main}
item3 -> 3  thread: <NSThread: 0x7fbf2cc0e7e0>{number = 1, name = main}
item3 -> 4  thread: <NSThread: 0x7fbf2cc0e7e0>{number = 1, name = main}
//用户的串行队列加入同步任务也是在主线程执行
let serialQueue = DispatchQueue(label: "serial")
serialQueue.sync(execute: item2)//同步任务结果:
item2 -> 0  thread: <NSThread: 0x7fbf2cc0e7e0>{number = 1, name = main}
item2 -> 1  thread: <NSThread: 0x7fbf2cc0e7e0>{number = 1, name = main}
item2 -> 2  thread: <NSThread: 0x7fbf2cc0e7e0>{number = 1, name = main}
item2 -> 3  thread: <NSThread: 0x7fbf2cc0e7e0>{number = 1, name = main}
item2 -> 4  thread: <NSThread: 0x7fbf2cc0e7e0>{number = 1, name = main}


参考文章:详解Swift多线程 | licc

一天精通iOS Swift多线程(GCD) - 掘金

更多推荐

GCD多线程基本使用

本文发布于:2024-03-09 15:54:11,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1725421.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:多线程   GCD

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!