iOS开发实践之多线程(GCD)

时间:2022-03-30 05:21:09

 什么是GCD: 

    1、GCD是苹果开发的一个多核编程的解决方法,和其它多线程技术方案相比,使用起来更加简单和方便.  
    2、纯C语言,提供了非常多强大的函数


GCD的优势:  

    1、GCD是苹果公司为多核的并行运算提出的解决方案   
   2、GCD会自动利用更多的CPU内核(比如双核、四核)   
   3、GCD会自动管理线程的生命周期(创建线程、调度任务、销毁线程)  
   4、程序员只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码


 队列和任务:

     GCD中有2个核心概念  

      任务:执行什么操作,用block来封装任务。

      队列:用来存放任务。

     将任务添加到队列中GCD会自动将队列中的任务取出,放到对应的线程中执行。

     任务的取出遵循队列的FIFO原则:先进先出,后进后出 。

   队列的类型

并发队列:可以让多个任务并发(同时)执行(自动开启多个线程同时执行任务),并发功能只有在异步(dispatch_async)函数下才有效。

      1、获得全局的并发队列

 //dispatch_queue_priority_t priority:队列的优先级
//unsigned long flags:此参数暂时无用,用0即可
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
     全局并发队列的优先级
    #define DISPATCH_QUEUE_PRIORITY_HIGH 2 // 高
    #define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 // 默认(中)
    #define DISPATCH_QUEUE_PRIORITY_LOW (-2) // 低
    #define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN// 后台


     串行队列:让任务一个接着一个地执行(一个任务执行完毕后,再执行下一个任务)。  

     1、使用dispatch_queue_create函数创建串行队列

//const char *label:队列名称
//dispatch_queue_attr_t attr:队列属性,一般用NULL即可
dispatch_queue_t queue = dispatch_queue_create("cn.XXX",NULL);
dispatch_release(queue); // 非ARC需要释放手动创建的队列

    2、使用主队列(跟主线程相关联的队列),主队列是GCD自带的一种特殊的串行队列
     放在主队列中的任务,都会放到主线程中执行
     使用dispatch_get_main_queue()获得主队列

dispatch_queue_t queue = dispatch_get_main_queue();


   执行任务:

1、用同步的方式执行任务

dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);

2、用异步的方式执行任务
dispatch_async(dispatch_queue_t queue, dispatch_block_t block);


   同步和异步的区别:
1、同步:只能在当前线程中执行任务,不具备开启新线程的能力。dispatch_sync

2、异步:可以在新的线程中执行任务,具备开启新线程的能力。 dispatch_async



  队列和执行任务方式组合分析:

   ps 特别注意:使用sync函数往当前串行队列中添加任务,会卡住当前的串行队列

iOS开发实践之多线程(GCD)

/**
* 异步全局并发
* async并发队列(最常用)
* 会创建线程,一般同时开多条
* 并发执行
**/
-(void)asyncGlobalQueue{
//获取全局并发队列
//dispatch_queue_priority_t priority:队列的优先级
//unsigned long flags:此参数暂时无用,用0即可
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

//将任务添加到全局队列中去异步执行
dispatch_async(queue, ^{
NSLog(@"------下载图片1----%@",[NSThread currentThread]);
});

dispatch_async(queue, ^{
NSLog(@"-----下载图片2-----%@",[NSThread currentThread]);
});

dispatch_async(queue, ^{
NSLog(@"----下载图片3------%@",[NSThread currentThread]);
});

dispatch_async(queue, ^{
NSLog(@"-----下载图片4----%@",[NSThread currentThread]);
});

}

/**
* 串行队列(有时候会用)
* 会创建线程,一般只开一条
* 串行执行,(一个任务执行完毕后再执行下一个任务)
**/
-(void)asyncSerialQueue{
//创建串行队列
//const char *label:队列名称
//dispatch_queue_attr_t attr:队列属性,一般用NULL即可
dispatch_queue_t queue = dispatch_queue_create("cn.XXX",NULL);

//将任务添加到串行队列中 异步执行
dispatch_async(queue,^{
NSLog(@"--------下载图片1---------%@",[NSThread currentThread]);
});

dispatch_async(queue, ^{
NSLog(@"--------下载图片2---------%@",[NSThread currentThread]);
});

dispatch_async(queue, ^{
NSLog(@"--------下载图片3---------%@",[NSThread currentThread]);
});

dispatch_async(queue, ^{
NSLog(@"--------下载图片4---------%@",[NSThread currentThread]);
});

dispatch_async(queue, ^{
NSLog(@"--------下载图片5---------%@",[NSThread currentThread]);
});

}

/**
* async --主队列(很常用)
**/
-(void)asyncMainQueue{
//主队列(添加到主队列中的任务,都会自动放到主线程中去执行)
dispatch_queue_t queue = dispatch_get_main_queue();

//添加任务到主队列中异步执行
dispatch_async(queue, ^{
NSLog(@"--------下载图片1---------%@",[NSThread currentThread]);
});

dispatch_async(queue, ^{
NSLog(@"--------下载图片2---------%@",[NSThread currentThread]);
});

dispatch_async(queue, ^{
NSLog(@"--------下载图片3---------%@",[NSThread currentThread]);
});

dispatch_async(queue, ^{
NSLog(@"--------下载图片4---------%@",[NSThread currentThread]);
});

dispatch_async(queue, ^{
NSLog(@"--------下载图片5---------%@",[NSThread currentThread]);
});

}

/**
* sync --主队列(不能用,会卡死)
**/
-(void)syncMainQueue{
//主队列(添加到主队列中的任务,都会自动放到线程中去执行)
dispatch_queue_t queue = dispatch_get_main_queue();

//将任务添加到主队列中同步执行
dispatch_sync(queue, ^{
NSLog(@"--------下载图片1---------%@",[NSThread currentThread]);
});

dispatch_sync(queue, ^{
NSLog(@"--------下载图片2---------%@",[NSThread currentThread]);
});

dispatch_sync(queue, ^{
NSLog(@"--------下载图片3---------%@",[NSThread currentThread]);
});

dispatch_sync(queue, ^{
NSLog(@"--------下载图片4---------%@",[NSThread currentThread]);
});

dispatch_sync(queue, ^{
NSLog(@"--------下载图片5---------%@",[NSThread currentThread]);
});
}


/**
* sync --并发队列
* 不会创建线程
* 串行执行(一个任务执行完毕后再执行下一个任务)
* 并发队列失去了并发的功能
**/
-(void)syncGlobalQueue{
//获取全局的并发队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

//将任务添加到全局并发队列中同步执行
dispatch_sync(queue, ^{
NSLog(@"--------下载图片1---------%@",[NSThread currentThread]);
});

dispatch_sync(queue, ^{
NSLog(@"--------下载图片2---------%@",[NSThread currentThread]);
});

dispatch_sync(queue, ^{
NSLog(@"--------下载图片3---------%@",[NSThread currentThread]);
});

dispatch_sync(queue, ^{
NSLog(@"--------下载图片4---------%@",[NSThread currentThread]);
});

dispatch_sync(queue, ^{
NSLog(@"--------下载图片5---------%@",[NSThread currentThread]);
});
}

/**
* sync --串行队列
* 不会创建线程
* 串行执行(一个任务执行完毕后再执行下一个任务)
**/
-(void)syncSerialQueue{
//创建一个串行队列
dispatch_queue_t queue = dispatch_queue_create("cn.xxx", NULL);

//将任务添加到串行队列中同步执行
dispatch_sync(queue, ^{
NSLog(@"--------下载图片1---------%@",[NSThread currentThread]);
});

dispatch_sync(queue, ^{
NSLog(@"--------下载图片2---------%@",[NSThread currentThread]);
});

dispatch_sync(queue, ^{
NSLog(@"--------下载图片3---------%@",[NSThread currentThread]);
});

dispatch_sync(queue, ^{
NSLog(@"--------下载图片4---------%@",[NSThread currentThread]);
});

dispatch_sync(queue, ^{
NSLog(@"--------下载图片5---------%@",[NSThread currentThread]);
});
}


    一次性执行:

 //一次性执行
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
//<#code to be executed once#>
});

    延时执行:

//延时执行(2秒)
double delayInSeconds = 2;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// <#code to be executed after a specified delay#>
});


    线程组:后台并发执行线程,等所有线程执行结束后再汇总执行结果

//1、获取线程组
dispatch_group_t group = dispatch_group_create();

//2、并行执行线程
dispatch_group_async(group, queue, ^{
//并发执行线程一
);
ispatch_group_async(group, queue, ^{
//并发执行线程二
});

//3、所有线程执行完成后调用
dispatch_group_notify(group, queue, ^{
//汇总结果
});


线程间通信

从子线程回到主线程
dispatch_async(
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // 执行耗时的异步操作...
      dispatch_async(dispatch_get_main_queue(), ^{
        // 回到主线程,执行UI刷新操作
        });
});


例子:子线程下载图片,下载后更新界面的imageView.

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
//子线程下载图片
NSURL *url = [NSURL URLWithString:@"http://d.hiphotos.baidu.com/image/pic/item/37d3d539b6003af3290eaf5d362ac65c1038b652.jpg"];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data];

//回到主线程
dispatch_queue_t mainQueue = dispatch_get_main_queue();
dispatch_async(mainQueue, ^{
self.imageView.image = image;
});
});
}