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 NSString
dictionary.setValue(center, forKey: "centerText")
array.add(dictionary)
}
array.write(toFile: filePath, atomically: false)
bodydata = origindata
}
else
{
for item in plistdata!{
let data = item as! NSDictionary
let center = data.value(forKey: "centerText") as! String
let sss = EditModel(centerText: center)
if(bodydata.count == 5)
{
break
}
else
{
bodydata.append(sss)
}
}
}//切换到主线程刷新UI
DispatchQueue.main.async {
self.tableview.reloadData()
}
}
}
基础认识
首先是队列的调度方式:并行和串行
并行:在本文中指并行队列,多个任务放在并行队列里执行,可以同时运行
串行:在本文中指串行队列,多个任务放在串行队列里执行,只能按顺序依次运行,前一个运行完成,下一个才能开始运行;前一个没运行完,后一个只能排队等着。以此类推,直到所有任务都运行完成。
并行
并发
任务的执行方式:同步和异步
同步:同步执行任务,在一个线程当中必须按顺序执行,执行结束的顺序也是固定的,而且同步任务会阻塞当前线程,直到同步任务结束才会结束阻塞,同步任务会经常造成线程的循环等待而导致死锁,慎用。
异步:异步执行任务,也是按顺序执行多项任务,但是是放在多个线程里同时运行,线程当中各个任务的开始执行时间和任务结束时间不固定,总耗时大约是耗时最长的那项任务所消耗的时间。
调度队列的种类:主队列,全局队列,自定义串行队列,自定义并行队列。
主队列(Main queue,串行队列):UI刷新的相关操作必须放在主队列
let mainQueue = DispatchQueue.main
全局队列(Global queue,并行队列):运行在后台线程,是系统内共享的全局队列,是一种并行队列(Concurrent),用于处理并发任务。因为是系统内共享,不单单属于这一个app,所以栅栏函数在全局队列中无效,为了避免堵塞其他程序的任务。
1,全局队列没有名字,但是并发队列有名字。有名字可以便于查看系统日志
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
原文地址:https://blog.csdn.net/qq_55655826/article/details/123543692
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_30974.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!