GCD Grand central Dispatch

  上一章我们讨论了iOS中的网络部分的进程线程多线程的相关知识,并且初步了解了NSThread的操作。但是NSThread是有问题的。比如在某个实例,我们需要在当tableView 中显示许多的cell,而cell上是来自网络加载的图片数据。那么我们需要在代理方法中调用cell的时候对imageView添加图片。传统的UIImageView的setImage方法是在主线程中执行的。图片较少的情况下是看不出什么卡顿的效果。但是如果图片的数量很多的情况下如果不使用cell复用,xib下显示100张图片就会卡的要死。

使用NSThread方法 

 NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(loadImageWithUrl:) object:app.imageUrl];

-(void)loadImageWithUrl:(NSString*)urlStr{

    NSLog(@"loadImageWithUrl:%@",[NSThread currentThread]);

    

    //同步下载一个图片

    NSURL *url = [NSURL URLWithString:urlStr];

    NSData *data = [NSData dataWithContentsOfURL:url];

    UIImage *image = [UIImage imageWithData:data];

   //刷一下UI

  self.iconImageView.image = image;

}

依然看不出什么性能上的改变。

我们修改代码,将刷新UI的代码修改为:

[self.iconImageView performSelectorInMainThread:@selector(setImage:)withObject:image waitUntilDone:nil];

即在主线程中运行。会发现程序更卡。

那么该怎么做?

GCD。

在这里修改代码,setApp:(AppModel*)model

{

//获取队列

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0);

//派遣线程任务

dispatch_async(queue,^{

[self loadImageViewWithUrl:model.imageUrl];

});

}

这样效率大大提升。

接下来详细介绍一下GCD。

GCD,全称:Grand Central Dispatch 多线程优化技术,定义了一套底层api,基于c语言开发的多线程机制,它提供了新的模式,编写并发执行的程序。

GCD的特点:

1。允许将一个程序切分为单一的任务,然后提交到工作队列中并发或者串行地执行。

2.为多核的并行计算提出了解决方案,自动合理利用cpu内核。

3.自动管理线程的生命周期 包括创建线程,调度任务,销毁线程,派遣任务,完全不用为我们管理。

4.基本上一些任务的代码是通过block。

概念2:Queue队列

GCD使用了队列的概念。解决了NSThread难以管理的问题

特点:1.顺序执行先进先出。

2.管理多线程,管理并发任务 设置主线程。

3.GCD是任务的队列 而不是线程的队列。

概念3:任务 任务在GCD中 就是在block中设置的执行代码。

有两种执行方式,1)同步执行:只要是同步任务 都会在当前线程,不会另外开启线程。2)异步执行:只要是异步任务 都会开启新线程,在新线程中执行。

概念4:队列分类 

1)串行队列 依次完成任务

2)并行队列 在同一时刻并发执行多个任务。

此外还涉及到 主队列,全局队列,自创建队列等。

GCD主要涉及到三种队列形式,自定义队列 全局队列 主队列等。

程序一:自定义队列

-(void)viewDidLoad

{

  [super viewDidLoad];

    [self createMyQueues];

}

同步队列

-(void)createQueue
{
    dispatch_queue_t queue = dispatch_queue_create("MyQueue", NULL);
    //同步队列
    dispatch_sync(queue, ^{
        [self work];
        [self eat];
    });
}
#pragma mark - 任务
-(void)eat
{
    int i = 0;
    while (i ++<10) {
        NSLog(@"吃%d",i);
        [NSThread sleepForTimeInterval:1.0];
    }
}
-(void)work
{
    int i = 0;
    while (i++ <10) {
        NSLog(@"我是%d",i);
        [NSThread sleepForTimeInterval:1.0];
    }
}

执行结果为:

2015-09-16 21:12:00.636 gcd复习[5790:304856] 我是1
2015-09-16 21:12:01.637 gcd复习[5790:304856] 我是2
2015-09-16 21:12:02.640 gcd复习[5790:304856] 我是3
2015-09-16 21:12:03.640 gcd复习[5790:304856] 我是4
2015-09-16 21:12:04.641 gcd复习[5790:304856] 我是5
2015-09-16 21:12:05.644 gcd复习[5790:304856] 我是6
2015-09-16 21:12:06.649 gcd复习[5790:304856] 我是7
2015-09-16 21:12:07.652 gcd复习[5790:304856] 我是8
2015-09-16 21:12:08.654 gcd复习[5790:304856] 我是9
2015-09-16 21:12:09.656 gcd复习[5790:304856] 我是10
2015-09-16 21:12:10.660 gcd复习[5790:304856] 吃1
2015-09-16 21:12:11.661 gcd复习[5790:304856] 吃2
2015-09-16 21:12:12.664 gcd复习[5790:304856] 吃3
2015-09-16 21:12:13.666 gcd复习[5790:304856] 吃4
2015-09-16 21:12:14.670 gcd复习[5790:304856] 吃5
2015-09-16 21:12:15.672 gcd复习[5790:304856] 吃6
2015-09-16 21:12:16.673 gcd复习[5790:304856] 吃7
2015-09-16 21:12:17.674 gcd复习[5790:304856] 吃8
2015-09-16 21:12:18.675 gcd复习[5790:304856] 吃9
2015-09-16 21:12:19.676 gcd复习[5790:304856] 吃10

可以看出 两个任务是串行执行,即同步。此时需要注意的是,这里的线程是主线程,并没有新建任何线程。

异步队列:

dispatch_async(queue, ^{

        [self work];

        [self eat];

    });

执行结果:

2015-09-16 21:18:09.586 gcd复习[5905:308576] 我是9
2015-09-16 21:18:10.588 gcd复习[5905:308576] <NSThread: 0x7fd7a8423070>{number = 1, name = main}
2015-09-16 21:18:10.588 gcd复习[5905:308576] 我是10
2015-09-16 21:18:11.593 gcd复习[5905:308576] <NSThread: 0x7fd7a8423070>{number = 1, name = main}
2015-09-16 21:18:11.593 gcd复习[5905:308576] 吃1
2015-09-16 21:18:12.596 gcd复习[5905:308576] <NSThread: 0x7fd7a8423070>{number = 1, name = main}
2015-09-16 21:18:12.596 gcd复习[5905:308576] 吃2
2015-09-16 21:18:13.599 gcd复习[5905:308576] <NSThread: 0x7fd7a8423070>{number = 1, name = main}
2015-09-16 21:18:13.599 gcd复习[5905:308576] 吃3
2015-09-16 21:18:14.600 gcd复习[5905:308576] <NSThread: 0x7fd7a8423070>{number = 1, name = main}
2015-09-16 21:18:14.600 gcd复习[5905:308576] 吃4

从以上执行结果可以看出 当前异步队列下 开辟了一个新的线程,且两个任务串行执行在该子线程中。

需要注意的是,异步队列下,程序会在两个线程中执行。

以以下代码为例

dispatch_async(queue, ^{
        [self print1];
//        [self print2];
    });
    //
    dispatch_async(queue1, ^{
//        [self print1];
        [self print2];
    });

当前的异步队列下会创建一个新的线程,所以当前的print1 print2函数会并发执行。

如果我想让程序在线程任务执行完毕之后执行另外的一件事情,那么需要用到队列组。

//创建队列组
    dispatch_group_t group = dispatch_group_create();
    
    //将事件统一到组中。
    dispatch_group_async(group, queue1, ^{
        NSLog(@"%@",[NSThread currentThread]);
        [self print1];
    });
    
    dispatch_group_async(group, queue2, ^{
        NSLog(@"%@",[NSThread currentThread]);
        [self print2];
    });
    
    dispatch_group_async(group, queue3, ^{
        NSLog(@"%@",[NSThread currentThread]);
        [self print3];
    });
    
    dispatch_group_async(group, queue4, ^{
        NSLog(@"%@",[NSThread currentThread]);
        [self print4];
    });
#pragma mark - 多队列任务
-(void)print1
{
    for (int i = 0; i < 10; i++) {
        NSLog(@"第1个任务执行,%d步",i);
        [NSThread sleepForTimeInterval:1.0];
    }
}
-(void)print2
{
    for (int i = 0; i < 10; i++) {
        NSLog(@"第2个任务执行,%d步",i);
        [NSThread sleepForTimeInterval:1.0];
    }
}
-(void)print3
{
    for (int i = 0; i < 10; i++) {
        NSLog(@"第3个任务执行,%d步",i);
        [NSThread sleepForTimeInterval:1.0];
    }
}
-(void)print4
{
    for (int i = 0; i < 10; i++) {
        NSLog(@"第4个任务执行,%d步",i);
        [NSThread sleepForTimeInterval:1.0];
    }
}
dispatch_group_notify(group, queue5, ^{
        NSLog(@"%d",[NSThread isMultiThreaded]);
        NSLog(@"--%@",[NSThread currentThread]);
        NSLog(@"%@",@"完成了");
    });

在所有任务执行完成之后该方法会执行。但是并不会创建新线程。

实例2 获取全局队列

特点:

        1.可以同时运行多个任务,每个任务的启动时间是按照加入queue的顺序执行的

        2.我们不能自己创建并调度全局队列,只有三个可用的线程

-(void)getGlobalQueue
{
    dispatch_group_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
    dispatch_async(queue, ^{
        NSLog(@"queue:%@",[NSThread currentThread]);
        [self print1];
        //[self print2];
    });
    
    dispatch_async(queue, ^{
        NSLog(@"queue:%@",[NSThread currentThread]);
        [self print3];
        //[self print4];
    });
}

运行结果如下

2015-09-16 22:39:14.680 gcd复习[6738:347874] <NSThread: 0x7fa90be12f90>{number = 1, name = main}
2015-09-16 22:39:14.681 gcd复习[6738:347959] queue:<NSThread: 0x7fa90be22b40>{number = 2, name = (null)}
2015-09-16 22:39:14.681 gcd复习[6738:347959] 第3个任务执行,0步
2015-09-16 22:39:14.682 gcd复习[6738:347960] queue:<NSThread: 0x7fa90bd24300>{number = 3, name = (null)}
2015-09-16 22:39:14.682 gcd复习[6738:347960] 第1个任务执行,0步
2015-09-16 22:39:15.682 gcd复习[6738:347959] 第3个任务执行,1步
2015-09-16 22:39:15.683 gcd复习[6738:347960] 第1个任务执行,1步
2015-09-16 22:39:16.684 gcd复习[6738:347960] 第1个任务执行,2步
2015-09-16 22:39:16.684 gcd复习[6738:347959] 第3个任务执行,2步
2015-09-16 22:39:17.685 gcd复习[6738:347959] 第3个任务执行,3步
2015-09-16 22:39:17.685 gcd复习[6738:347960] 第1个任务执行,3步
2015-09-16 22:39:18.688 gcd复习[6738:347960] 第1个任务执行,4步
2015-09-16 22:39:18.688 gcd复习[6738:347959] 第3个任务执行,4步
2015-09-16 22:39:19.689 gcd复习[6738:347959] 第3个任务执行,5步
2015-09-16 22:39:19.689 gcd复习[6738:347960] 第1个任务执行,5步
2015-09-16 22:39:20.690 gcd复习[6738:347959] 第3个任务执行,6步
2015-09-16 22:39:20.690 gcd复习[6738:347960] 第1个任务执行,6步
2015-09-16 22:39:21.692 gcd复习[6738:347960] 第1个任务执行,7步
2015-09-16 22:39:21.692 gcd复习[6738:347959] 第3个任务执行,7步
2015-09-16 22:39:22.693 gcd复习[6738:347960] 第1个任务执行,8步
2015-09-16 22:39:22.693 gcd复习[6738:347959] 第3个任务执行,8步
2015-09-16 22:39:23.698 gcd复习[6738:347959] 第3个任务执行,9步
2015-09-16 22:39:23.698 gcd复习[6738:347960] 第1个任务执行,9步

从以上可以看出 异步队列创建了两个新的线程 并且并行执行这两个任务。

-(void)getGlobalQueue
{
    dispatch_group_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
    dispatch_async(queue, ^{
        NSLog(@"queue:%@",[NSThread currentThread]);
        [self print1];
        //[self print2];
    });
    
    dispatch_sync(queue, ^{
        NSLog(@"queue--:%@",[NSThread currentThread]);
        [self print3];
        //[self print4];
    });
}

如以上写法 则在同步方法中不会创建新的线程。任务并行执行。

实例3:主队列

//获取主队列
-(void)getMainQueue
{
    dispatch_async(dispatch_get_main_queue(), ^{
        for (int i = 0; i <10; i ++) {
            NSLog(@"%@",[NSThread currentThread]);
            NSLog(@"multi:%d",[NSThread isMultiThreaded]);
            NSLog(@"main:%d",[NSThread isMultiThreaded]);
            sleep(1.0);
        }
    });
}

以上就是GCD今天的讨论内容了。

转载于:https://www.cnblogs.com/mosuyanxue/p/4814844.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值