在咱们实际开发中, 有不免会遇到一些问题, 好比我要从网上下载一张图片进行修改, 这里就涉及到线程的问题了, 还有就是咱们日常使用的下载工具: 迅雷, QQ旋风之类的, 它们能够进行同时下载, 也能够一个一个的来下载, 在这里咱们称之为同步和异步, 顾名思义, 所谓的同步就是全部文件一块儿下载, 异步就是把须要下载的文件一个个排好队来下载.程序员
在开始说多线程以前, 咱们要知道两样东西, 一个是进程, 一个是线程:面试
进程: 正在进行中的程序就叫作进程, 负责程序运行的内存分配, 每个进程都有本身独立的虚拟内存空间.编程
线程: 线程是进程中一个独立的执行路径(控制单元), 一个进程中至少包含一条线程(主线程), 能够将耗时的操做或者执行放到另外一个线程里.后端
说白了, 进程就是为程序分配内存的, 而线程就是用来控制程序代码的实际运行.安全
举个例子, 咱们的程序运行, 都是按照代码从上往下的执行, 但若是遇到须要下载图片的时候, 它就会卡在这里, 等待图片下载完成才会执行下一步, 这样子就不符合咱们的实际体验了, 因此咱们会把下载图片放到子线程里去操做, 等到下载完成以后才传回给主线程, 这就是多线程的好处, 既不会影响主线程的运行, 又能够完成下载图片的任务.markdown
提示:
1.dispatch_async 异步操做,会并发执⾏,没法肯定任务的执⾏顺序
2.dispatch_sync 同步操做,会依次顺序执⾏,可以决定任务的执行顺序多线程
PS: 线程是有限的, 不能够无休止的增长, 而主线程的大小只有1MB, 子线程都是512KB.并发
串行队列: 队列中的任务只会顺序执⾏异步
func gcdDemo1() {
// 将操做放在队列中
// 在 C 语言函数中, 定义类型, 绝大多数都是以_t或者ref 结尾
// 使用串行队列的异步任务, 能够节省资源, 新建线程是须要有资源消耗的, 不能无休止的去新建线程
// 应用案例:
// 从网上下载图片
// 滤镜(高光, 红眼...)
var q: dispatch_queue_t = dispatch_queue_create("com.cain.gcdDemo1", DISPATCH_QUEUE_SERIAL)
let i = 0
for i in 0...10 {
dispatch_async(q, { () -> Void in
println(NSThread.currentThread())
})
}
// 非 ARC 开发时, 必定要 release
// dispatch_release(q);
// 串行队列的同步任务, 也会在主线程中运行
// 在实际开发中, 极少人用
// 面试又可能会用到
for i in 0...9 {
// 同步任务, 顺序执行
dispatch_async(q, { () -> Void in
println("\(NSThread.currentThread()) - \(i)")
})
}
}
并行队列: 队列中的任务一般会并发执⾏async
func gcdDemo2() {
// 特色: 没有顺序, 程序员不可控
// 应用场景: 并发执行的, 没有前后顺序
// 并行队列容易出错, 并行队列建立的子线程数量一样是不可控
var q: dispatch_queue_t = dispatch_queue_create("com.cain.gcdDemo2", DISPATCH_QUEUE_CONCURRENT)
for i in 0...9 {
// 同步任务
dispatch_sync(q, { () -> Void in
println("\(NSThread.currentThread()) - \(i)")
})
// 异步任务
dispatch_async(q, { () -> Void in
// [NSThread currentThread] 能够在开发中跟踪当前的线程.
// number = 1表示主线程
// number = 2或者其余, 表示子线程, 这里是2, 因此是第2个子线程
println("\(NSThread.currentThread()) - \(i)")
})
}
}
全局队列
func gcdDemo3() {
// 全局队列与并行队列的区别
// 1< 不须要建立, 直接GET就可使用
// 2< 两个队列的执行效果相同
// 3< 全局队列没有名称, 调试时没法确认准确队列
var q: dispatch_queue_t = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
for i in 0...9 {
// 异步任务
dispatch_async(q, { () -> Void in
println("\(NSThread.currentThread()) - \(i)")
})
// 同步任务
dispatch_sync(q, { () -> Void in
println("\(NSThread.currentThread()) - \(i)")
})
}
}
主线程队列
func gcdDemo4() {
var q = dispatch_get_main_queue()
for i in 0...9 {
// 异步任务, 并发执行, 保持队形的
dispatch_async(q, { () -> Void in println("\(NSThread.currentThread()) - \(i)") }); // 同步任务 // 注意, 在主线程队列中不可使用同步任务, 不然会形成线程阻塞 // dispatch_sync(q, { () -> Void in // println("come here baby!") // }); } }
串⾏队列
1.同步任务, 不须要新建线程, 异步任务, 须要⼀个⼦线程, 线程的建立和回收不须要程序员参与!
2.“是最安全的一个选择”串⾏行队列只能建立!
并行队列
1.同步任务, 不须要建立线程并行队列, 异步任务, 有多少个任务, 就开N个线程执⾏行 不管什么队列和什么任务, 线程的建立和回收不须要程序员参与.
2.线程的建立回收⼯做是由队列负责的 “并发”编程, 为了让程序员从负责的线程控制中解脱出来! 只须要⾯对队列和任务!
GCD的好处
1.经过GCD, 开发者不⽤再直接跟线程打交道, 只须要向队列中添加代码块便可.
2.GCD在后端管理着⼀个线程池, GCD不只决定着代码块将在哪一个线程被执⾏, 它还根据可用的系统资源对这些线程进⾏管理. 从而让开发者从线程管理的工做中解放出来, 经过集中的管理线程, 缓解大量线程被建立的问题.
3.使⽤用GCD, 开发者能够将工做考虑为一个队列, 而不是一堆线程,这种并行的抽象模型更容易掌握和使⽤.
GCD的队列
1.GCD公开有5个不一样的队列: 运⾏在主线程中的主队列, 3个不一样优先级的后台队列, 以及一个优先级更低的后台队列(⽤于 I/O).
2.⾃定义队列: 串⾏行和并⾏行队列, ⾃定义队列⾮常强大,建议在开发中使⽤, 在⾃定义队列中被调度的全部Block最终都将被放⼊到系统的全局队列中和线程池中.
提示: 不建议使⽤用不一样优先级的队列, 由于若是设计不当, 可能会出现优先级反转, 即低优先级的操做阻塞⾼优先级的操做.
好了, 此次咱们就讲到这里, 下次咱们继续~~