Description
Grand Central Dispatch
framework to automatically manage the threads' lifecycle: create, dispatch, reuse, dealloc
How to use
- custom task
- push into DispatchQueue, queue is FIFO, but not First in, First execute
- wait DispatchQueue logic and run the task
queue determine how to run tasks
- concurrent queue: execute by maxConcurrentCount
- serial queue: execute one by one
- async / sync determine create new thread or not
- async: create new thread
- sync: blocking current thread and execute in current thread
- async, wait for DispatchQueue to run
- sync, run in current thread at once
API
// 主队列:
//OBJECTIVE-C
dispatch_queue_t queue = ispatch_get_main_queue();
//OBJECTIVE-C
//串行队列
dispatch_queue_t queue= dispatch_queue_create("tk.bourne.testQueue", NULL);
dispatch_queue_t queue= dispatch_queue_create("tk.bourne.testQueue", DISPATCH_QUEUE_SERIAL);
//并行队列
dispatch_queue_t queue= dispatch_queue_create("tk.bourne.testQueue", DISPATCH_QUEUE_CONCURRENT);
// 全局并行队列
//OBJECTIVE-C
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// main queue
DispatchQueue.main.async { }
DispatchQueue.main.async(execute: ()->Void)
// global concurrent queue
DispatchQueue.global().async {}
DispatchQueue.global().async(execute: ()->Void)
DispatchQueue.global().async(execute: DispatchWorkItem)
DispatchQueue.global().asyncAfter(deadline: DispatchTime, execute: ()->Void)
DispatchQueue.global().asyncAfter(deadline: DispatchTIme, execute: DispatchWorkItem)
// create serial queue
let serialQueue = DispatchQueue(label: "serialQueue")
let serialQueue1 = DispatchQueue(__label: "serialQueue1", attr: nil)
// create concurrent queue
let concurrentQueue = DispatchQueue(label: "concurrentQueue1", attributes: .concurrent)
优势:
自动管理线程的生命周期(create,schedule,release)
GCD 核心: 任务 && 队列
- 定制任务
- 将任务添加队列中 FIFO, 但不一定谁先执行
- Concurrent Queue(开启多个线程让多个任务同时执行)
- Serial Queue (一个接一个执行)
async 和 sync决定能不能开启线程,
async 和 sync 决定要不要阻塞当前线程
queue决定如何执行任务
异步函数等会儿执行,同步函数马上执行, 并阻塞当前线程
GCD 主要方法:
- DispatchQueue.queueName.sync { } //在当前线程之行,不具备开启新线程的能力
- DispatchQueue.queueName.async {} //可能开启新线程
队列创建
类型
- Concurrent Queue(允许开启多个线程让多个任务同时执行)
- Serial Queue (一个接一个执行)
创建
dispatch_queue_t queue = dispatch_queue_create("name", DISPATCH_QUEUE_SERIAL/DISPATCH_QUEUE_CONCURENT);
// create serial queue
let serialQueue = DispatchQueue("serialQueue")
let serialQueue1 = DispatchQueue("SerialQueue1", DISPATCH_QUEUE_SERIAL)
// create concurrent queue
let concurrentQueue = DispatchQueue("ConcurrentQueue", DISPATCH_QUEUE_CONCURRENT)
全局队列
dispatch_get_global_queue(优先级, 0);//并发队列
dispatch_get_main_queue()//特殊的串行队列队列
DispatchQueue.main
DispatchQueue.global()
特殊
Main queue is serial,函数放到主队列异步也不会开启新线程
Main queue with sync task will cause Deadlock
GCD 其他函数
等待前面线程执行完再执行( For thread-safe)
dispatch_barrier_async(queue, block)
隔开任务,barrier前面的执行完在执行barrier的任务,barrier后面的在barrier执行完在执行
用global queue不行,必须自己建的队列
serial 队列用不着这么做,已经是串行一个个执行
// guarantee .barrier will run solely within the queue
// waiting for previous task done
// blocking the rest tasks
let concurrentQueue = DispatchQueue(label: "concurrentQueue1", attributes: .concurrent)
concurrentQueue.async(flags: .barrier) {
print("concurrentQueue barrier")
}
延后加入队列
dispatch_after(time, queue, block)
dispatch_once()static dispatch_once_t once; dispatch_once(once, block);
//里面的代码是线程安全的
//整个程序只加载一次,不能用于懒加载,懒加载是每个对象都能调用一次。反过来,用once,只有第一个对象能调用,
dispatch_apply(10, queue, block);
//同时遍历,queue必须是并发队列
DispatchQueue.global().asyncAfter(deadline: DispatchTime, execute: ()->Void)
DispatchQueue.global().asyncAfter(deadline: DispatchTIme, execute: DispatchWorkItem)
队列组 dispatch_group_async
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, block);
dispatch_group_notify(group, queue, block(执行完了));
/// DispatchGroup
// Create DispatchGroup
let group = DispatchGroup()
let lastBlockGCD = { () -> Void in
print("finish GCD \(Thread.current)")
}
var testBlock1 = { () -> Void in
print("block 1 in \(Thread.current)")
}
var testBlock2 = { () -> Void in
print("block 2 in \(Thread.current)")
}
var testBlock3 = { () -> Void in
print("block 3 in \(Thread.current)")
}
var testBlocks = Array<() -> Void>()
testBlocks.append(contentsOf: [testBlock1, testBlock2, testBlock3])
// add group task to queue
for block in testBlocks {
//let workItem = DispatchWorkItem(block: block)
//queue.async(group: group, execute: workItem)
concurrentQueue.async(group: group, execute: block)
}
// when group finished, hook up lastBlockGCD
group.notify(queue: concurrentQueue, execute: lastBlockGCD)
GCD 进程通信
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
// 图片的网络路径
NSURL*url = [NSURLURLWithString:
@"http://img.pconline.com.cn/images/photoblog/9/9/8/1/9981681/200910/11/1255259355826.jpg"\];
// 加载图片
NSData*data = [NSDatadataWithContentsOfURL:url];
// 生成图片
UIImage*image = [UIImageimageWithData:data];
// 回到主线程
dispatch_async(dispatch_get_main_queue(), ^{
self.imageView.image = image;
});
});
func updateImageView(urlString: String, imageView: UIImageView?) {
guard let imageView = imageView,
let url = URL(string: urlString) else {
return
}
DispatchQueue.global().async {
if let data = try? Data(contentsOf: url),
let image = UIImage(data: data) {
DispatchQueue.main.async {
imageView.image = image
}
}
}
}
DispatchQueue.once {}
from http://www.jianshu.com/p/640b64faea9a
public extension DispatchQueue {
private static var _onceTracker = [String]()
/**
Executes a block of code, associated with a unique token, only once. The code is thread safe and will
only execute the code once even in the presence of multithreaded calls.
- parameter token: A unique reverse DNS style name such as com.vectorform.<name> or a GUID
- parameter block: Block to execute once
*/
public class func once(token: String, block:()->Void) {
// add sync lock
objc_sync_enter(self)
defer { objc_sync_exit(self) }
if _onceTracker.contains(token) {
return
}
_onceTracker.append(token)
block()
}
}
DispatchQueue.once(token: "com.vectorform.test") {
print( "Do This Once!" )
}
private let _onceToken = NSUUID().uuidString
DispatchQueue.once(token: _onceToken) {
print( "Do This Once!" )
}