理解线程

GCD

Posted by MAYBESHEWILL on May 5, 2017

含义

首先我们来理解 GCD 的含义:

  • GCD全称是Grand Central Dispatch

  • GCD是苹果公司为多核的并行运算提出的解决方案

  • GCD会自动利用更多的CPU内核(比如双核、四核)

  • GCD会自动管理线程的生命周期(创建线程、调度任务、销毁线程)

再来理解 串并行,同异步:

串行队列同步执行: 在当前线程顺序执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
dispatch_queue_t queue =  dispatch_queue_create("queneName", NULL);
 //2.添加任务到队列中,就可以执行任务
dispatch_sync(queue, ^{
    NSLog(@"下载图片1----%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
    NSLog(@"下载图片2----%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
    NSLog(@"下载图片3----%@",[NSThread currentThread]);
});
    //打印主线程
NSLog(@"主线程----%@",[NSThread mainThread]);

下载图片1----<NSThread: 0x600002b20240>{number = 1, name = main}
下载图片2----<NSThread: 0x600002b20240>{number = 1, name = main}
下载图片3----<NSThread: 0x600002b20240>{number = 1, name = main}
主线程----<NSThread: 0x600002b20240>{number = 1, name = main}

不会开启新的线程,创建的自定义队列无效。

串行队列异步执行: 开辟一条新的线程,在该线程中顺序执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    dispatch_queue_t queue =  dispatch_queue_create("queneName", NULL);
    //2.添加任务到队列中,就可以执行任务
dispatch_async(queue, ^{
    NSLog(@"下载图片1----%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
    NSLog(@"下载图片2----%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
    NSLog(@"下载图片3----%@",[NSThread currentThread]);
});
    //打印主线程
NSLog(@"主线程----%@",[NSThread mainThread]);

下载图片1----<NSThread: 0x600001308040>{number = 5, name = (null)}
下载图片2----<NSThread: 0x600001308040>{number = 5, name = (null)}
下载图片3----<NSThread: 0x600001308040>{number = 5, name = (null)}
主线程----<NSThread: 0x600001344840>{number = 1, name = main}

异步串行执行3个任务,只会开启一个子线程。

并行队列同步执行: 不开新线程,在当前线程顺序执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
        //获取全局并发队列
dispatch_queue_t queue =  dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    //2.添加任务到队列中,就可以执行任务
dispatch_sync(queue, ^{
    NSLog(@"下载图片1----%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
    NSLog(@"下载图片2----%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
    NSLog(@"下载图片3----%@",[NSThread currentThread]);
});
    //打印主线程
NSLog(@"主线程----%@",[NSThread mainThread]);

下载图片1----<NSThread: 0x600001420080>{number = 1, name = main}
下载图片2----<NSThread: 0x600001420080>{number = 1, name = main}
下载图片3----<NSThread: 0x600001420080>{number = 1, name = main}
主线程----<NSThread: 0x600001420080>{number = 1, name = main}

不会开启新的线程,并发队列失去了并发的功能。

并行队列异步执行:开辟多个线程,无序执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
   //获取全局并发队列
dispatch_queue_t queue =  dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//2.添加任务到队列中,就可以执行任务
dispatch_async(queue, ^{
   NSLog(@"下载图片1----%@",[NSThread currentThread]);
   });
dispatch_async(queue, ^{
   NSLog(@"下载图片2----%@",[NSThread currentThread]);
       });
dispatch_async(queue, ^{
   NSLog(@"下载图片3----%@",[NSThread currentThread]);
    });
//打印主线程
NSLog(@"主线程----%@",[NSThread mainThread]);

下载图片3----<NSThread: 0x600000af9680>{number = 5, name = (null)}
下载图片2----<NSThread: 0x600000afdac0>{number = 7, name = (null)}
下载图片1----<NSThread: 0x600000ae0200>{number = 6, name = (null)}
主线程----<NSThread: 0x600000ab8d40>{number = 1, name = main}

异步并发执行3个任务,会开启3个子线程。

主队列异步执行: 不开新线程,同步执行

1
2
3
4
5
6
7
dispatch_async(dispatch_get_main_queue(), ^{
    NSLog(@"111111");
});
NSLog(@"222222");

2019-01-16 10:28:57.254042+0800 GCD[463:148602] 222222
2019-01-16 10:28:57.277710+0800 GCD[463:148602] 111111

主队列同步执行: 会造成死锁.

1
2
3
4
5
6
7
⚠️ BOOM!

dispatch_sync(dispatch_get_main_queue(), ^{
   NSLog(@"111111");
});
 
NSLog(@"222222")

总结

总结一下就是:

  • 同异步决定了要不要去开辟一个新的线程.
  • 串并行决定了任务的执行方式.

当然除了上边的方法,创建一个串行队列也可以用:

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

    1
    
    dispatch_queue_t queue = dispatch_queue_create("queneName", NULL); // 创建
    
  2. 还有就是主队列是 GCD 自带的一个特殊的串行队列

    1
    
    dispatch_queue_t queue = dispatch_get_main_queue();
    

创建一个串行队列也可以用 dispatch_get_global_queue函数获得全局的并发队列

1
2
3
4
5
6
7
8
9
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 // 后台

尝试用图表总结一下下:

文章使用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议