要了解GCD的使用首先我们需要去了解 进程、线程 以及二者之间的关系,同时也需要去知道多线程的一些特点
一、 进程:
1.进程是一个具有一定独立功能的程序关于某次数据集合的一次运行活动,它是操作系统分配资源的基本单元.
2.进程是指在系统中正在运行的一个应用程序,就是一段程序的执行过程,我们可以理解为手机上的一个app.
3.每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内,拥有独立运行所需的全部资源
二、 线程
1.程序执行流的最小单元,线程是进程中的一个实体.
2.一个进程要想执行任务,必须至少有一条线程.应用程序启动的时候,系统会默认开启一条线程,也就是主线程
三、 进程和线程的关系
1.线程是进程的执行单元,进程的所有任务都在线程中执行
2.线程是 CPU 分配资源和调度的最小单位
3.一个程序可以对应多个进程(多进程),一个进程中可有多个线程,但至少要有一条线程
4.同一个进程内的线程共享进程资源
四、 多线程
1.同一时间,CPU只能处理1条线程,只有1条线程在执行。多线程并发执行,其实是CPU快速地在多条线程之间调度(切换)。如果CPU调度线程的时间足够快,就造成了多线程并发执行的假象
2.如果线程非常非常多,CPU会在N多线程之间调度,消耗大量的CPU资源,每条线程被调度执行的频次会降低(线程的执行效率降低)
3.多线程的优点:
能适当提高程序的执行效率
能适当提高资源利用率(CPU、内存利用率)
4.多线程的缺点:
开启线程需要占用一定的内存空间(默认情况下,主线程占用1M,子线程占用512KB),如果开启大量的线程,会占用大量的内存空间,降低程序的性能
线程越多,CPU在调度线程上的开销就越大
程序设计更加复杂:比如线程之间的通信、多线程的数据共享
下面直接上代码吧。。。。
//同步任务 串行队列
NSLog(@"\n\n同步任务");
dispatch_queue_t queue = dispatch_queue_create("this.is.a.queue", DISPATCH_QUEUE_SERIAL);
dispatch_sync(queue, ^{
NSLog(@"同步任务 %@", [NSThread currentThread]);
});
//异步任务 串行队列
NSLog(@"\n\n异步任务");
dispatch_queue_t queue1 = dispatch_queue_create("this.is.a.queue", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue1, ^{
NSLog(@"异步任务 %@", [NSThread currentThread]);
});
//串行队列(同步串行)
NSLog(@"\n\n串行队列");
dispatch_queue_t queue33 = dispatch_queue_create("this.is.a.queue", DISPATCH_QUEUE_SERIAL);
dispatch_sync(queue33, ^{
for (NSInteger i = 0; i < 5; i++) {
NSLog(@"串行队列任务1_i:%ld %@", i, [NSThread currentThread]);
[NSThread sleepForTimeInterval:1];
}
});
dispatch_sync(queue33, ^{
for (NSInteger i = 0; i < 5; i++) {
NSLog(@"串行队列任务1_i:%ld %@", i, [NSThread currentThread]);
[NSThread sleepForTimeInterval:2];
}
});
//串行队列(异步串行)//开启了新的线程
NSLog(@"\n\n串行队列");
dispatch_queue_t queue3 = dispatch_queue_create("this.is.a.queue", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue3, ^{
for (NSInteger i = 0; i < 5; i++) {
NSLog(@"串行队列任务1_i:%ld %@", i, [NSThread currentThread]);
[NSThread sleepForTimeInterval:1];
}
});
dispatch_async(queue3, ^{
for (NSInteger i = 0; i < 5; i++) {
NSLog(@"串行队列任务2_i:%ld %@", i, [NSThread currentThread]);
[NSThread sleepForTimeInterval:2];
}
});
//并发队列(异步)
NSLog(@"\n\n并发队列");
dispatch_queue_t queue4 = dispatch_queue_create("this.is.a.queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue4, ^{
for (NSInteger i = 0; i < 5; i++) {
NSLog(@"异步并发队列任务1_i:%ld %@", i, [NSThread currentThread]);
[NSThread sleepForTimeInterval:1];
}
});
dispatch_async(queue4, ^{
for (NSInteger i = 0; i < 5; i++) {
NSLog(@"异步并发队列任务2_i:%ld %@", i, [NSThread currentThread]);
[NSThread sleepForTimeInterval:2];
}
});
/**结果
* 异步并发队列任务1_i:0 {number = 6, name = (null)}
* 异步并发队列任务2_i:0 {number = 5, name = (null)}
* 异步并发队列任务1_i:1 {number = 6, name = (null)}
* 异步并发队列任务2_i:1 {number = 5, name = (null)}
* 异步并发队列任务1_i:2 {number = 6, name = (null)}
* 异步并发队列任务1_i:3 {number = 6, name = (null)}
* 异步并发队列任务2_i:2 {number = 5, name = (null)}
* 异步并发队列任务1_i:4 {number = 6, name = (null)}
* 异步并发队列任务2_i:3 {number = 5, name = (null)}
* 异步并发队列任务2_i:4 {number = 5, name = (null)}
*/
//并发队列(同步)
NSLog(@"\n\n并发队列");
dispatch_queue_t queue44 = dispatch_queue_create("this.is.a.queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_sync(queue44, ^{
for (NSInteger i = 0; i < 5; i++) {
NSLog(@"并发队列任务1_i:%ld %@", i, [NSThread currentThread]);
[NSThread sleepForTimeInterval:1];
}
});
dispatch_sync(queue44, ^{
for (NSInteger i = 0; i < 5; i++) {
NSLog(@"并发队列任务2_i:%ld %@", i, [NSThread currentThread]);
[NSThread sleepForTimeInterval:2];
}
});
/**结果
* 同步并发队列任务1_i:0 {number = 1, name = main}
* 同步并发队列任务1_i:1 {number = 1, name = main}
* 同步并发队列任务1_i:2 {number = 1, name = main}
* 同步并发队列任务1_i:3 {number = 1, name = main}
* 同步并发队列任务1_i:4 {number = 1, name = main}
* 同步并发队列任务2_i:0 {number = 1, name = main}
* 同步并发队列任务2_i:1 {number = 1, name = main}
* 同步并发队列任务2_i:2 {number = 1, name = main}
* 同步并发队列任务2_i:3 {number = 1, name = main}
* 同步并发队列任务2_i:4 {number = 1, name = main}
*/
//执行完之前的任务再执行后面的任务:
NSLog(@"\n\n执行完之前的任务再执行后面的任务");
dispatch_queue_t queue5 = dispatch_queue_create("this.is.a.queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue5, ^{
for (NSInteger i = 0; i < 5; i++) {
NSLog(@"并发队列任务1_i:%ld %@", i, [NSThread currentThread]);
[NSThread sleepForTimeInterval:1];
}
});
//此时的queue 不能是全局的并发队列
//dispatch_barrier_async 前面的任务先执行,后面的任务恢复原本规则执行
dispatch_barrier_async(queue5, ^{
NSLog(@"并发队列任务4");
});
dispatch_async(queue5, ^{
for (NSInteger i = 0; i < 5; i++) {
NSLog(@"并发队列任务2_i:%ld %@", i, [NSThread currentThread]);
[NSThread sleepForTimeInterval:2];
}
});
dispatch_async(queue5, ^{
for (NSInteger i = 0; i < 5; i++) {
NSLog(@"并发队列任务3_i:%ld %@", i, [NSThread currentThread]);
[NSThread sleepForTimeInterval:3];
}
});
/**结果
* 异步并发队列任务1_i:0 {number = 5, name = (null)}
* 异步并发队列任务1_i:1 {number = 5, name = (null)}
* 异步并发队列任务1_i:2 {number = 5, name = (null)}
* 异步并发队列任务1_i:3 {number = 5, name = (null)}
* 异步并发队列任务1_i:4 {number = 5, name = (null)}
* 异步并发队列任务3
* 异步并发队列任务2_i:0 {number = 5, name = (null)}
* 异步并发队列任务3_i:0 {number = 3, name = (null)}
* 异步并发队列任务2_i:1 {number = 5, name = (null)}
* 异步并发队列任务3_i:1 {number = 3, name = (null)}
* 异步并发队列任务2_i:2 {number = 5, name = (null)}
* 异步并发队列任务3_i:2 {number = 3, name = (null)}
* 异步并发队列任务2_i:3 {number = 5, name = (null)}
* 异步并发队列任务2_i:4 {number = 5, name = (null)}
* 异步并发队列任务3_i:3 {number = 3, name = (null)}
* 异步并发队列任务3_i:4 {number = 3, name = (null)}
*/
//使用主线程
NSLog(@"\n\n使用主线程");
dispatch_queue_t mainQueue = dispatch_get_main_queue();
dispatch_async(mainQueue, ^{
NSLog(@"使用主线程 %@", [NSThread currentThread]);
});
//全局并发线程,用法和并发队列一致:
NSLog(@"\n\n全局并发线程");
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(globalQueue, ^{
NSLog(@"全局并发线程 %@", [NSThread currentThread]);
});
//倒计时的实现
/**
* 1、获取主线程
* 2、dispatch_time_t 设置延迟时间 第一个参数 默认 DISPATCH_TIME_NOW 第二个参数设置的是延迟的具体时间 单位纳秒 NSEC_PER_SEC 单位秒
* 3、dispatch_after 是延迟时间之后的 任务块代码(实现延迟执行时需要)参数一是 dispatch_time_t 参数二是 主线程
* 4、创建调度资源
* 5、dispatch_source_set_timer 计时器的方法实现{
1、参数一:调度资源
* 2、参数二:任务延迟时间即任务开始执行时间
* 3、参数三:时间间隔
* 4、参数四:余度 纳秒的回旋余地
* }
* 注:调度资源 dispatch_source 不能为成员变量
*/
double delayInSeconds = 2.0;
dispatch_queue_t mainQueue2 = dispatch_get_main_queue();
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));//多久之后开始执行,时间是
// dispatch_after(popTime, mainQueue, ^{
// NSLog(@"延时执行的2秒 %@", [NSThread currentThread]);
// });
self.sourceTime = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, mainQueue2);
dispatch_source_set_timer(self.sourceTime, popTime, (int64_t)(5 * NSEC_PER_SEC), 0);
dispatch_source_set_event_handler(self.sourceTime, ^{
NSLog(@"计时器 %@", [NSThread currentThread]);
});
dispatch_resume(self.sourceTime);
//dispatch_group_t调度
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_queue_create("this.is.a.queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_async(group, queue, ^{
sleep(8);
NSLog(@"1111 %@", [NSThread currentThread]);
});
dispatch_group_async(group, queue, ^{
NSLog(@"2222 %@", [NSThread currentThread]);
});
//当group上的任务都执行完成了调用
dispatch_group_notify(group, queue, ^{
NSLog(@"3333 %@", [NSThread currentThread]);
});
//当group上的任务都执行完了调用或者时间已经超过了设定的5秒调用
dispatch_async(dispatch_get_global_queue(0, 0), ^{
dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC));
NSLog(@"dispatch_group_wait 结束 %@", [NSThread currentThread]);
});
//使用 dispatch_group_enter 和 dispatch_group_leave 来处理异步线程的同步问题,这两个方法必须是要成对出现的,当 dispatch_group_leave 完成就回回调 dispatch_group_notify ,使用的时候可以比较灵活。
dispatch_group_t group2 = dispatch_group_create();
dispatch_group_enter(group2);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
sleep(3);
NSLog(@"任务一完成 %@", [NSThread currentThread]);
dispatch_group_leave(group2);
});
dispatch_group_enter(group2);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"任务二完成 %@", [NSThread currentThread]);
sleep(5);
NSLog(@"任务三完成 %@", [NSThread currentThread]);
dispatch_group_leave(group2);
});
dispatch_group_notify(group2, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"任务完成 %@", [NSThread currentThread]);
});
/**结果
* 任务二完成 {number = 7, name = (null)}
* 任务一完成 {number = 6, name = (null)}
* 任务三完成 {number = 7, name = (null)}
* 任务完成 {number = 7, name = (null)}
*/
注:只有异步线程才具备开启新线程的能力(并不一定开启新线程),同步是不能开启新线程
串行队列(Serial Dispatch Queue):
同一时间内,队列中只能执行一个任务,只有当前的任务执行完成之后,才能执行下一个任务。(只开启一个线程,一个任务执行完毕后,再执行下一个任务)。主队列是主线程上的一个串行队列,是系统自动为我们创建的
并发队列(Concurrent Dispatch Queue):
同时允许多个任务并发执行。(可以开启多个线程,并且同时执行任务)。并发队列的并发功能只有在异步(dispatch_async)函数下才有效