GCD学习

一 .基础
1.GCD队列
GCD(Grand Central Dispatch)是从OS X Snow Leopard和iOS 4开始引入的新一代的多线程编程技术,使用起来较为方便;GCD队列主要分为3种

1.程序员自建队列, dispatch_queue_create;
2.系统本身必须有主线程—线程上必然有一个队列,这就是主队列
3.系统提供了 异步(非主线程)的队列,称为全局队列,全局队列为并行队列

2.同步 异步 并行 串行的理解
异步串行: i 和 j 打印, i打印完毕再打印j, 在同一个线程

异步并行: i和j 的打印是在不同线程里执行的,是无序的. 这个线程肯定不是主线程—-最常用的,效率最高

同步串行: 线程是主线程, 任务执行是有序的(不常用)
我们正常写代码都是同步串行, 当从分线程中回到主线程,刷新UI的时候 可以调用

同步并行: 同于 同步串行. 因为同步表示必须在主线程中运行, 并行 有需要的话,可以开分线程—-遵循同步的规则,只能在主线程中

3.GCD队列创建
GCD队列创建方式:

//第一参数:队列名称;  第二个参数:枚举类型,选择并行还是串行
( DISPATCH_QUEUE_CONCURRENT 为并行;  DISPATCH_QUEUE_SERIAL 为串行;)
dispatch_queue_t queue = dispatch_queue_create("", DISPATCH_QUEUE_CONCURRENT);

对于串行队列,每创建一个串行队列,系统就会对应创建一个线程,同时这些线程都是并行执行的,只是在串行队列中的任务是串行执行的。大量的创建串行队列会导致大量消耗内存,这是不可取的做法。串行队列的优势在于他是一个线程,所以在操作一个全局数据时候是线程安全的。当想并行执行而不发生数据竞争时候可以用并行队列操作

Main Dispatch Queue是在主线程中执行任务的Dispatch Queue。因为主线程只有1个,所以Main Dispatch Queue是Serial Dispatch Queue。追加到Main Dispatch Queue中的任务将在主线程的RunLoop中执行。因为是在主线程中执行,所以应该只将用户界面更新等一些必须在主线程中执行的任务追加到Main Dispatch Queue中。

dispatch_queue_t dispatch_main_queue = dispatch_get_main_queue();

Global Dispatch Queue是所有应用程序都能使用的Concurrent Dispatch Queue。大多数情况下,可以不必通过dispatch_queue_create函数生成Concurrent Dispatch Queue,而是只要获取Global Dispatch Queue使用即可。Global Dispatch Queue有4个优先级,分别是:High、Default、Low、Background。

dispatch_queue_t dispatch_global_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

4.线程的创建

dispatch_async(queue, ^{
        NSLog(@"dispatch-2 %@", [NSThread currentThread]);
    });//异步  async;

dispatch_sync(queue, ^{
        NSLog(@"dispatch-2 %@", [NSThread currentThread]);
    });//同步  sync;

二 .dispatch_group
如果想在dispatch_queue中所有的任务执行完成后在做某种操作,在串行队列中,可以把该操作放到最后一个任务执行完成后继续,但是在并行队列中怎么做呢。这就有dispatch_group 成组操作。比如

dispatch_queue_t dispatchQueue = dispatch_queue_create("ted.queue.next", DISPATCH_QUEUE_CONCURRENT);
    dispatch_group_t dispatchGroup = dispatch_group_create();
    dispatch_group_async(dispatchGroup, dispatchQueue, ^(){
        NSLog(@"dispatch-1");
    });
    dispatch_group_async(dispatchGroup, dispatchQueue, ^(){
        NSLog(@"dspatch-2");
    });
    dispatch_group_async(dispatchGroup, dispatchQueue, ^(){
        NSLog(@"dspatch-3");
    });
    dispatch_group_async(dispatchGroup, dispatchQueue, ^(){
        NSLog(@"dspatch-4");
    });
    dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^(){
        NSLog(@"end");
    });//dispatch_group_notify函数用来指定一个额外的block,该block将在group中所有任务完成后执行

上面的1 2 3 4输出顺序不定,因为是在并行队列上执行,当并行队列全部执行完成后,最后到main队列上执行一个操作,保证“end”是最后输出。 另外,这里也可以不用创建自己的并行队列,用全局的global,那个也是个并行队列. dispatch_get_gloable_queue(0,0);

三.dispatch_barrier_async

dispatch_barrier_async 阻断 作用是在并行队列中,让之前的并行操作先执行完毕 再执行之后的操作

dispatch_queue_t queue = dispatch_queue_create("", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^(){
        NSLog(@"dispatch-1");
    });
    dispatch_async(queue, ^(){
        NSLog(@"dispatch-2");
    });
    dispatch_barrier_async(queue, ^(){
        NSLog(@"dispatch-barrier"); 
    });
    dispatch_async(queue, ^(){
        NSLog(@"dispatch-3");
    });
    dispatch_async(queue, ^(){
        NSLog(@"dispatch-4");
    });

这里1 2将会先并行输出 再输出dispath_barrier 再并行输出3 4;

四.dispatch_apply

功能:把一项任务提交到队列中多次执行,具体是并行执行还是串行执行由队列本身决定.注意,dispatch_apply不会立刻返回,在执行完毕后才会返回,是同步的调用。
这是dispatch_apply函数的基本样子;

//参数一:执行次数
//参数二:提交到的队列
//参数三:操作
dispatch_apply(<#size_t iterations#>, <#dispatch_queue_t queue#>, <#^(size_t)block#>)
NSArray *array = [NSArray arrayWithObjects:@"1",@"2",@"3",@"4",@"5",nil];
        dispatch_async(dispatch_get_global_queue(0, 0), ^(){
        dispatch_apply([array count], dispatch_get_global_queue(0, 0), ^(size_t index){
            NSLog(@"index-%ld", index);
            NSString *str = [array objectAtIndex:index];
            NSLog(@"str-%@",str);
        });
        NSLog(@"done");
    });

输出结果

 index-0
 index-1
 index-3
 index-2
 str- 3
 str- 2
 str- 1
 index-4
 str- 5
 str- 4
 done

输出 index 顺序不确定,因为它是并行执行的(dispatch_get_global_queue是并行队列),但是done是在以上拷贝操作完成后才会执行,因此,它一般都是放在dispatch_async里面(异步)。实际上,这里 dispatch_apply如果换成串行队列上,则会依次输出index,但这样违背了我们想并行提高执行效率的初衷。

五.dispatch_after

在说dispatch_after之前要先提一下dispatch_time_t :
dispatch_time函数能够获取从第一个参数dispatch_tiem_t类型值指定的时间开始,到第二个参数指定的毫秒单位时间后的时间,函数原型如下

//参数一:参数经常使用的值是DISPATCH_TIME_NOW,表示现在的时间
//参数二:是等待时间
        //#define NSEC_PER_SEC 1000000000ull  1秒
        //#define NSEC_PER_MSEC 1000000ull    1毫秒
        //#define USEC_PER_SEC 1000000ull     1毫秒
        //#define NSEC_PER_USEC 1000ull       1纳秒
dispatch_time_t time = dispatch_time(<#dispatch_time_t when#>, <#int64_t delta#>)

dispatch_after
功能:延迟一段时间把一项任务提交到队列中执行,返回之后就不能取消,常用来在在主队列上延迟执行一项任务

//参数一:过了多久执行的时间间隔
//参数二:提交到的队列
//参数三:执行的任务
dispatch_after(<#dispatch_time_t when#>, <#dispatch_queue_t queue#>, <#^(void)block#>)
NSDate *startDate=[NSDate date];
    NSLog(@"startDate---%@",startDate);
    dispatch_time_t time=dispatch_time(DISPATCH_TIME_NOW, 30*NSEC_PER_SEC);
    dispatch_after(time, dispatch_get_main_queue(), ^{
        NSLog(@"test");
        NSDate *endDate=[NSDate date];
        NSLog(@"endDate1---%@",endDate);
    });
    NSDate *endDate=[NSDate date];
    NSLog(@"endDate2---%@",endDate);

输出:

startData---2016-04-15 06:19:42 +0000
endDate2---2016-04-15 06:19:42 +0000
test
endDate1---2016-04-15 06:20:12 +0000

六.dispatch_once
功能:保证在APP运行期间,block中的代码只执行一次
这十分适合单例,这里写个单例的例子

- (NSObject*)shareObject
{
    static NSObject* object = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken,^{
        object = [[NSObject alloc]init];
    });
    return object;

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值