GCD理解
来源:互联网 发布:软件 会展 编辑:程序博客网 时间:2024/06/04 19:46
GCD
GCD (Grand Central Dispatch) 是 libdispatch 的市场名称,而 libdispatch 作为 Apple 的一个库,为并发代码在多核硬件上执行提供有力支持。
在iOS多线程编程中,GCD占有相当重要的地位。因为相对于 NSThread 和 NSOperation, GCD的使用更简单方便并且实现了真正的硬件多核支持,开发者要做的只是定义想执行的任务并追加到适当的 Dispatch Queue中。
dispatch_queue
dispatch_queue 是一个执行处理的等待队列,是一个FIFo(先进先出)队列,这样就保证了先放进队列的任务能够
先执行。
dispatch_queue 是线程安全的,在并发任务中被调用时不会产生任务问题。所以可以放心使用。
dispatch_queu类型:
1) 串行 dispatch_queue 在串行队列一次只执行一个任务,并且按照我们添加到队列的顺序来执行。
在串行队列中,在同一个时间间隔内只有一个任务可以执行,当上一个任务结束后才会开始下一个任务。
2) 并发 dispatch_queue 在并发队列中一次可以执行多个,它们会按照被添加的顺序开始执行。
在并发队列中同一个时间间隔内可以有多个任务同时执行。
在并发队列中的任务可以不用等待现在执行中的处理结束,这样就可以并行执行多个处理,但并行执行的处理数量
取决于当前系统状态。即iOS和OS X 基于dispatch Queue中的处理数、cpu核心以及CPU负荷等当前系统的状态
来绝定Concurrent Dispatch Queue中执行的处理数。
- 并行:在同一时间内有多个任务执行
- 并发:在同一时间间隔内有多个任务执行
可以简单的理解为并发是一种能力,可以允许多个任务执行。并行是真正的在同一时间内执行多个任务。所以要想可以并行
首先必须可以并发。但并发不要求并行。并行在多核中执行起来相对容易,可以给每个核分配一个线程执行各自的任务。
但在单核中执行并行就不那么容易了,在单核中必须使用时间片轮转法。例如,有两个线程Thread1,Thread2,在一个时间
片内先执行Thread1的任务,然后保留现场,在一下个时间片执行Thread2,当时间片结束时保留现场并切换到Thrad1开始
下一个时间片.由于这个时间片相当相当短,给我们的感觉就是在同时执行。
dispatch_queu 创建
- 通过CGD API
func dispatch_queue_create(_ label: UnsafePointer<Int8>, _ attr: dispatch_queue_attr_t!) -> dispatch_queue_t!
每次调用 dispatch_queue_create 都会创建一个新的dispatch_queue_t和一个新的线程,所以过多的创建
dispatch_queue 会创建过多的线程,就会消耗大量内存,引起大量的上下文切换。这样多个线程的queue就行成了一个
并行的任务队列,这时候如果同时去写一个数据就可能出问题了。
2.获取系统中已存在的dispatch_queue
Main Dispatch Queue:在主线程中执行的串行dispatch_queue,因为主线程只有一个,所以Main Dispatch Queue也只存在一个。Main Dispatch 中的所有任务都是在主线程的runloop中执行的,跟NSObject的
performSelectOnMainThread一样。所以执行UI更新等需要在主线程中执行的任务必须添加到Main Dispatch
queue中.
Global Dispatch Queue:全局可用的并行队列。队列有4个执行的优先等级。High Priority, Default
Low, BackGround.
实战使用
- 在子线程执行耗时的操作避免阻塞界面,在主线程中更新界面
dispatch_queue_t mainQueue = dispatch_get_main_queue(); dispatch_async(mainQueue, ^{ // 刷新UI }); dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0); dispatch_async(globalQueue, ^{ // 费时且不需要阻塞线程的操作 });
dispatch_async(dispatch_get_global_queue(0, 0), { () -> Void in let url:NSURL = NSURL(string:"http://7xlgnt.com1.z0.glb.clouddn.com/Serial.png")! let imageData: NSData? = NSData(contentsOfURL:url) dispatch_async(dispatch_get_main_queue(), { () -> Void in if let imageData = imageData { imageView.image = UIImage(data: imageData) } }) })
- 延时操作 dispatch_after
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,Int64(1 * NSEC_PER_SEC)), dispatch_get_global_queue(0, 0)) { () -> Void in print("come here") } dispatch_after(dispatch_time(DISPATCH_TIME_NOW,Int64(1 * NSEC_PER_MSEC)), dispatch_get_global_queue(0, 0)) { () -> Void in print("come here2") } dispatch_after(dispatch_time(DISPATCH_TIME_NOW,Int64(1 * NSEC_PER_USEC)), dispatch_get_global_queue(0, 0)) { () -> Void in print("come here3") }
我们先看几个值
print(NSEC_PER_SEC) 结果: 1000000000 皮秒 1000000000 = 1秒
print(NSEC_PER_MSEC) 结果: 1000000 微妙 1000000 = 1 秒
print(NSEC_PER_USEC) 结果: 1000 毫秒 1000 毫秒 = 1秒
print(DISPATCH_TIME_NOW) 0
print(DISPATCH_TIME_FOREVER) 18446744073709551615
print(UInt64.max) 18446744073709551615
public func dispatch_time(when: dispatch_time_t, _ delta: Int64) -> dispatch_time_t
when 什么时候开始计算延迟,是一个Uint64的值, 这里的值都是皮秒
_delta 延迟多少皮秒执行。
要延迟1秒我们可以这样:
dispatch_time(DISPATCH_TIME_NOW,Int64(1 * NSEC_PER_SEC)
dispatch_time(DISPATCH_TIME_NOW,Int64(1000 * NSEC_PER_MSEC)
dispatch_time(DISPATCH_TIME_NOW,Int64(1000000 * NSEC_PER_USEC)
所以上面的代码执行结果是:
come here3
come here2
come here
- 保证只执行一次的 dispatch_once
public func dispatch_once(predicate: UnsafeMutablePointer, _ block: dispatch_block_t)
单例是我们在代码中最常见的只执行一次的例子。有如下一个类
class Car { var name:String? static var car:Car? class func shareInstance() -> Car { if (car == nil) { car = Car() print("开始初始化") } return car! }}
上面的类中有一个shareInstance的方法来生成一个单例对象,但是上面的方法并不是线程安全的,如果在多线程中执行上述方法就会产问题
dispatch_async(dispatch_get_global_queue(0, 0)) { () -> Void in var car = Car.shareInstance() }; dispatch_async(dispatch_get_global_queue(0, 0)) { () -> Void in var car = Car.shareInstance() }; dispatch_async(dispatch_get_global_queue(0, 0)) { () -> Void in var car = Car.shareInstance() };
执行时我们可以看到输出了三次 “开始初始化”,这说明car == nil并不能有效的去判断当前是不是已经开始初始化了,因为当第
一个的初始化还未完成时第二个的初始已经开始了,然后第三个也开始初始化,所以说看到输出了三个“开始初始化”
class Car { var name:String? class var shareInstance:Car { struct Static { static var car:Car? static var onceToken : dispatch_once_t = 0 } dispatch_once(&Static.onceToken) { () -> Void in Static.car = Car() } return Static.car! }}
如果换成上面的代码使用dispatch_once,就会变成线程安全了。
- GCD理解
- GCD理解
- iOS GCD 理解
- GCD 深入理解
- GCD 深入理解
- GCD 的简单理解
- GCD的一点理解
- GCD 深入理解一
- GCD 深入理解二
- GCD理解(一)
- GCD理解(二)
- GCD理解(三)
- GCD深入理解
- GCD--我的理解
- GCD 深入理解
- 深入理解GCD(一)
- 快速理解GCD
- GCD任务、队列理解
- 一个简单的python socket程序
- @property 那些事
- C# 泛型理解之大白话
- HLSL中的内置函数
- htc one x 紧急充电脚本,解决无法充电,变砖,电量过低等问题
- GCD理解
- Java的Socket通信(多Clients/Server模型)
- 最大子数组差
- Android的5种数据存储方式之sharedpreference
- 获取ServerSocket信息的方法及FTP原理
- The Basics Of Image Filtering
- Installation error: INSTALL_PARSE_FAILED_MANIFEST_MALFORMED
- Craftyjs系列2-Scene
- 你会解吗? ?+?+?=30 把下面数字填到框里 (1,3,5,7,9,11,13,15)