iOS多线程编程之GCD
2015-12-02 本文已影响40人
华子小筑
文章资料来源《Objective-C高级编程》之GCD
GCD是一种异步执行任务的技术,对于编程层面上异步执行就意味着创建一个线程(操作系统能夠進行運算调度的最小單位,是进程中一个单一顺序的控制流--from wiki)去执行Task;GCD提供了两种队列和相关API使得开发者只需要关心该选择哪种队列去执行任务即可;
GCD的队列
- serial queue 能够保证各个task在同一个线程中被执行并且执行顺序会严格的按照入队的顺序进行;
- concurrent queue 各个task的执行互不影响,执行顺序上不确定,执行线程也不一定会相同;
dispatch_queue_create 创建队列
serial queue
/*
1>serial Queue:系统默认创建一个线程,队列中的任务是顺序执行
2>创建多个serial queue 的执行是并发的没有顺序
3>解决数据竞争问题:可以将任务放在serial queue中 保证任务按照顺序执行就能解决数据竞争
*/
dispatch_queue_t mySerialQueue = dispatch_queue_create("com.hua.example.serialQueue", DISPATCH_QUEUE_SERIAL);
concurrent queue
/*
1 concurrent queue 添加到队列中的任务会并发执行,没有顺序性
*/
dispatch_queue_t myConcurrentQueue=dispatch_queue_create("com.hua.example.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
非ARC下生成的队列还必须使用dispatch_release(Queue);
来释放指定的队列
Main Dispatch Queue and Global Dispatch Queue
Main Dispatch Queue
/*
dispatch_get_main_queue
(1)main queue 是一中serial queue,task是放在主线程的Runloop中执行的;
(2)一些UI的更新操作需要放在主线程中,使用main queue是比较简单的
*/
dispatch_queue_t main_queue = dispatch_get_main_queue();
global Dispatch Queue
/*
dispatch_get_global_queue
(1)global queue 是一种concurrent queue,可以通过设置queue的priority指定执行的优先级;
*/
dispatch_queue_t global_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_set_target_queue
/*
dispatch_set_target_queue的第一个参数是指定要变更优先级的队列;指定与要使用优先级相同优先级的队列为第二个参数
*/
dispatch_queue_t serialqueue1 = dispatch_queue_create("serialqueue1", NULL);
dispatch_queue_t serialqueue2 = dispatch_queue_create("serialqueue2", NULL);
dispatch_set_target_queue(serialqueue2, serialqueue1);
/*
dispatch_after
/*
延迟若干时间处理某一个Task,只是追加task到某一个队列,并不一定立即执行task
*/
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 3*NSEC_PER_SEC);
dispatch_after(time, dispatch_get_main_queue(), ^{
NSLog(@"wait at least three seconds!!");
});
dispatch Group
dispatch group 的出现可以解决多个并发task执行后能收到通知再执行其他任务操作的需求;
/*
1; 如果使用 serial queue 所有的task执行完毕后在执行done task
2:如果使用 concurrent queue 所有的task执行后没办法 执行行done task 就需要 dispatch_group
*/
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();
//
dispatch_group_async(group, queue, ^{
NSLog(@"blok1");
});
dispatch_group_async(group, queue, ^{
NSLog(@"blok2");
});
dispatch_group_async(group, queue, ^{
NSLog(@"blok3");
});
dispatch_group_async(group, queue, ^{
[NSThread sleepForTimeInterval:2.0];
NSLog(@"blok4");
});
// 监听group 中的task 是否已经全部执行完成
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"done!!");
});
// dispatch_group_wait会hold住当前线程直到所有task执行完毕
// dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
NSLog(@"all finish!!!!");
多个网络请求执行操作完成在执行下一步操作的需求如何实现?
// 多个网络请求完成后再做新的任务
dispatch_group_enter(group);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//网络请求操作1
dispatch_group_leave(group);
});
dispatch_group_enter(group);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//网络请求操作2
dispatch_group_leave(group);
});
dispatch_barrier_async
多线程操作产生的一个问题就是数据资源的竞争,读写操作如何能保证线程安全性;dispatch_barrier_async提供了解决方案
/*
使用concurrent dispatch queue 和 dispatch barrier async 函数可实现高效率的数据库访问和文件读取
*/
dispatch_queue_t queue = dispatch_queue_create("test.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"task1forReading!");
});
dispatch_async(queue, ^{
NSLog(@"task2forReading!");
});
dispatch_async(queue, ^{
NSLog(@"task3forReading!");
});
dispatch_barrier_async(queue, ^{
// 此taskforWriting 会等到加入concurrentQueue中的task执行完毕后,执行taskforWriting,等到该taskforWriting执行完毕后在执行 concurrentQueue中的task
NSLog(@"taskforWriting!");
});
dispatch_async(queue, ^{
NSLog(@"task4forReading!");
});
dispatch_async(queue, ^{
NSLog(@"task5forReading!");
});
dispatch_sync
/*
dispatch_sync 函数意味着等待;它要等待task执行完毕后再做返回
*/
//使用dispatch_sync 容易造成死锁
//在主线程中执行以下源代码会造成死锁
/*
main_queue 是一个serialQueue ,使用dispatch_sync将task加入到mainqueue中task会等待mainqueue中的任务执行完成,而mainqueue又要等待task完成,由此造成了死锁;
*/
dispatch_queue_t main_queue = dispatch_get_main_queue();
dispatch_sync(main_queue, ^{
NSLog(@"hello dispatch_sync!");
});
//>2在主线程中执行以下源代码也会造成死锁
dispatch_async(main_queue, ^{
dispatch_sync(main_queue, ^{
NSLog(@"hello!!");
});
});
dispatch_apply
NSMutableArray* tempArr = [@[@"key1",@"key2",@"key3",@"key4",@"key5"] mutableCopy];
// 1 按照指定的次数将指定的Block追加到指定的Dispatch_Queue中,并等待全部处理执行结束
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_apply([tempArr count], queue, ^(size_t index) {
// 要做数据更新操作
NSLog(@"%d",index);
});
NSLog(@"task done");
/*
1 对数组进行循环遍历的方法
1》 for循环
2》 block
3》 dispatch_apply
2 dispatch_apply 要等待结束,最好和 dispatch_async函数混合使用
*/
挂起队列和执行队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//挂起队列
dispatch_suspend(queue);
//恢复指定队列
dispatch_resume(queue);
dispatch_Semaphore
// 1 向数组中增加对象由于内存错误导致异常的概率会很高
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
NSMutableArray* mutable_arr =[NSMutableArray array];
for(int i = 0;i<100000;++i)
{
dispatch_async(queue, ^{
[mutable_arr addObject:[NSNumber numberWithInt:i]];
});
}
// 2 使用dispatch_semaphore进行更细粒度的线程管理
dispatch_queue_t global_queue = dispatch_queue_create(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
/*
生成Dispatch Semahpore
dispatch_Semahpore 的计数初始值设定为“1”
这样能保证访问NSMutableArray类对象的线程,同时只有1个
*/
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
NSMutableArray* array =[NSMutableArray array];
for(int i = 0;i<10000;i++)
{
dispatch_async(global_queue, ^{
/*
等待Dispatch Semaphore
直到Dispatch Semphore的计数值达到大于等于1;
*/
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
/*
由于dispatch Semaphore 的计数值达到大于等于1
所以将Dispatch semaphore 的计数值减去1
dispatch_semaphore_wait 函数执行返回
执行到此 dispatch Semaphore的计数值恒为“0”
*/
[array addObject:[NSNumber numberWithInt:i]];
/*
排他控制处理结束,所以通过dispatch_semaphore_signal函数 将
Dispatch Semaphore的计数值加1
如果有通过dispatch_semaphore_wait 函数 等待dispatch Semaphore 的计数值增加的线程 就由最先等待的线程执行
*/
dispatch_semaphore_signal(semaphore);
});
}
dispatch_once
保证应用程序中只执行一次指定处理的API
+(instancetype)shareInstance
{
static ViewController* _vc;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_vc =[[self alloc] init];
});
return _vc;
}