程序员成长iOS-多线程疯狂iOS

GCD

2016-02-28  本文已影响337人  我是滕先生

概念解释

1. 执行任务的函数:在GCD中,任务是通过 block来封装的,并且任务的block没有参数也没有返回值。

同步:你必须把我的代码执行完你再走,一定要执行完同步里的代码再执行下面的代码

void dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);

异步:你先走执行我下面的代码,我找人、找线程去执行我里面的代码

void dispatch_async(dispatch_queue_t queue, dispatch_block_t block);

2. GCD使用步骤:

第一步: 创建/获取 队列
第二步: 创建任务,确定要做的事情
第三步: 将任务添加到队列中
(1)GCD会自动将队列中的任务取出,放到对应的线程中执行
(2)任务的取出遵循队列的FIFO原则: 先进先出,后进后出

3. 队列

包括: 串行队列、并发队列、主队列、全局队列

1. 串行队列(Serial Dispatch Queue)

串行队列的特点:
以先进先出的方式,按顺序调度队列中的任务去执行,一次只能调度一个任务。
无论队列中所指定的执行任务的函数是同步还是异步,都必须等待前一个任务执行完毕,才可以调度后面的任务。

串行队列的创建:

(1) dispatch_queue_tqueue = dispatch_queue_create("itheima", DISPATCH_QUEUE_SERIAL);
(2) dispatch_queue_tqueue = dispatch_queue_create("itheima", NULL);

串行队列,同步执行:
开不开线程? 不开线程。
顺序执行还是乱序执行? 顺序执行。

串行队列,异步执行:
开不开线程? 只会开一条线程。
顺序执行还是乱序执行? 顺序执行。

2. 并发队列(Concurrent Dispatch Queue)

并发队列的创建:

dispatch_queue_t q = dispatch_queue_create("itheima", DISPATCH_QUEUE_CONCURRENT);

并发队列,同步执行:
开不开线程? 不开线程。
顺序执行还是乱序执行? 顺序执行。
并发同步 和 串行同步的执行结果一模一样。

并发队列,异步执行:
开不开线程? 开多条新线程。
顺序执行还是乱序执行? 乱序执行。

3. 主队列:
- (void)demo1 {    
for (int i = 0; i < 10; i++) {       
NSLog(@"111");        
dispatch_async(dispatch_get_main_queue(), ^{            
NSLog(@"hello %d  %@",i,[NSThread currentThread]);
        });        
NSLog(@"222");        
NSLog(@"333");    
}
}
- (void)viewDidLoad {    
[super viewDidLoad];    
NSLog(@"begin");    
for (int i = 0; i < 10; i++) {        //死锁,一看同步就不分子线程了,一看主队列,就等着主线程执行完来执行里面代码       
dispatch_sync(dispatch_get_main_queue(), ^{            
NSLog(@"hello %d  %@",i,[NSThread currentThread]);        
});    }    
NSLog(@"end");
}

先执行begin和end,再顺序执行全局队列异步执行(第二个线程里执行)

- (void)demo3 {
    NSLog(@"begin");
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        for (int i = 0; i < 10; i++) {
            dispatch_sync(dispatch_get_main_queue(), ^{                
            NSLog(@"hello %d  %@",i,[NSThread currentThread]);            });        }
    });
    NSLog(@"end");
}
4. 全局队列:
    DISPATCH_QUEUE_PRIORITY_HIGH = 2; 高优先级
    DISPATCH_QUEUE_PRIORITY_DEFAULT = 0; 默认优先级
    DISPATCH_QUEUE_PRIORITY_LOW = -2; 低优先级
    DISPATCH_QUEUE_PRIORITY_BACKGROUND = INT16_MIN; 后台优先级
iOS8.0开始,推荐使用服务质量(QOS):
    QOS_CLASS_USER_INTERACTIVE  = 0x21; 用户交互
    QOS_CLASS_USER_INITIATED    = 0x19; 用户期望
    QOS_CLASS_DEFAULT         = 0x15; 默认
    QOS_CLASS_UTILITY         = 0x11; 实用工具
    QOS_CLASS_BACKGROUND      = 0x09; 后台
    QOS_CLASS_UNSPECIFIED       = 0x00; 未指定

通过对比可知: 第一个参数传入0,可以同时适配iOS7及iOS7以后的版本。
服务质量和优先级是一一对应的:

    DISPATCH_QUEUE_PRIORITY_HIGH:          QOS_CLASS_USER_INITIATED
    DISPATCH_QUEUE_PRIORITY_DEFAULT:      QOS_CLASS_DEFAULT
    DISPATCH_QUEUE_PRIORITY_LOW:           QOS_CLASS_UTILITY
    DISPATCH_QUEUE_PRIORITY_BACKGROUND:   QOS_CLASS_BACKGROUND

方法:

  1. 获取系统队列
    (1)获取主队列(一种串行队列) dispatch_queue_t 类型
dispatch_get_main_queue()

(2)获取全局队列(一种并发队列) dispatch_queue_t 类型

dispatch_get_global_queue(0, 0)
dispatch_queue_t dispatch_get_global_queue(long identifier, unsigned long flags);
  1. 自定义创建一个串行、并发队列
    参数1:队列名
    参数2:队列类型,串行还是并发队列
    串行队列:DISPATCH_QUEUE_SERIAL 或 NULL
    并发队列:DISPATCH_QUEUE_CONCURRENT
dispatch_queue_t dispatch_queue_create(const char *label, dispatch_queue_attr_t attr);

例子:创建一个串行队列

dispatch_queue_t queue = dispatch_queue_create("hm", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t queue = dispatch_queue_create("itheima", NULL);
  1. 创建任务
typedef void (^dispatch_block_t)(void);

例子:

dispatch_block_t task = ^{        
NSLog(@"hello %@",[NSThread currentThread]);
};
  1. 将任务添加到队列(参数1:队列 参数2:任务)
void dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
void dispatch_async(dispatch_queue_t queue, dispatch_block_t block);

例子:将任务同步添加到队列和将任务异步添加到队列

(1)dispatch_sync(queue, task);
(2)dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"hello %@",[NSThread currentThread]);
    });
  1. Barrier阻塞
void dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);
_queue = dispatch_queue_create("110", DISPATCH_QUEUE_CONCURRENT);
for (int i = 1; i<=10; i++) {    
[self downloadImage:i];}
-(void)downloadImage:(int)index {
    dispatch_async(_queue, ^{        //模拟下载图片        
    NSString *fileName = [NSString stringWithFormat:@"%02d.jpg",index % 10 + 1];        
    NSString *path = [[NSBundle mainBundle] pathForResource:fileName ofType:nil];
    UIImage *img = [UIImage imageWithContentsOfFile:path];
        //等待队列中所有的任务执行完成(十个图片下载完成任务),才会执行barrier中的代码
        dispatch_barrier_async(_queue, ^{            
[self.photoList addObject:img];            
NSLog(@"保存图片 %@   %@",fileName,[NSThread currentThread]);
        }); 
        NSLog(@"图片下载完成 %@  %@",fileName,[NSThread currentThread]);
    }); 
}
  1. 延时操作
void dispatch_after(dispatch_time_t when,
dispatch_queue_t queue,
dispatch_block_t block);
dispatch_time_t dispatch_time(dispatch_time_t when, int64_t delta);
#define DISPATCH_TIME_NOW (0ull)
#define DISPATCH_TIME_FOREVER (~0ull)
#define NSEC_PER_SEC 1000000000ull#define NSEC_PER_MSEC 1000000ull#define USEC_PER_SEC 1000000ull
#define NSEC_PER_USEC 1000ull
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
});
  1. 一次性执行
for (int i = 0; i<20000; i++) {    
static dispatch_once_t onceToken;    
dispatch_once(&onceToken, ^{        
NSLog(@"hello %@",[NSThread currentThread]);    });
}
  1. 调度组
dispatch_group_t group = dispatch_group_create();

(3)监听调度组内队列任务是否执行完毕:把任务添加到队列中,队列添加到调度组中,队列任务执行完毕通知调度组

void dispatch_group_async(dispatch_group_t group,
dispatch_queue_t queue,
dispatch_block_t block);

(4)接收到调度组执行完毕的通知后,执行其它任务

void dispatch_group_notify(dispatch_group_t group,
dispatch_queue_t queue,
dispatch_block_t block);

例子:

//创建组
dispatch_group_t group = dispatch_group_create();
//队列
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
//下载第一首歌曲
dispatch_group_async(group, queue, ^{
    NSLog(@"正在下载第一个歌曲");
});
//下载第二首歌曲
dispatch_group_async(group, queue, ^{    
NSLog(@"正在下载第二个歌曲");
    [NSThread sleepForTimeInterval:2.0];
});//下载第三首歌曲dispatch_group_async(group, queue, ^{    NSLog(@"正在下载第三个歌曲");
});
//当三个异步任务都执行完成,才执行dispatch_group_notify(group, dispatch_get_main_queue(), ^{    NSLog(@"over %@",[NSThread currentThread]);
});
上一篇 下一篇

猜你喜欢

热点阅读