你好,GCD

2018-04-01  本文已影响472人  顺其自然JX

1. 并行和并发有什么区别?

并行:同一时刻同时执行不同的任务, 关键点在于同时, 当然想达到这一点至少有两条线程;

并发:同一时间段可以执行不同的任务, 关键在于 可以执行不同的任务, 想做到这一点 一条线程也可以,因为可以在一条线程中交替执行, 多条线程也可以达到, 不同的线程中执行不同的任务;

2. 线程和进程?

进程:具有独立功能的关于某个数据集合上的第一次运行活动,是系统资源分配和调度的独立单位;
线程:是进程的一个实体,是CPU调度和分派的基本代为,它与同一进程中的其他线程共享该进程中所有资源;
区别:
1,一个程序至少一个进程,一个进程至少有一个线程;
2, 进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率
3, 线程的划分尺度小于进程,使得多线程程序的并发性高进程只能在一个时间干一件事,如果想同时干两件事或多件事,进程就无能为力了,同一个进程中的多个线程之间可以并发执行

收拾下心情,进入我们的主角GCD:

1、为什么要用GCD?

2、如何更好的理解任务和队列;

任务:你让程序干的事情,也就是程序需要执行哪些操作;GCD中通常block里面就是一系列的任务;]

任务

队列:队列是用来装任务的,管理任务的,不然任务就乱套了; 它采用FIFO先进先出的原则,不管是串行队列还是并发队列都是一样的,注意这里仅仅指的是出队列的顺序!!!

队列
如图:任务4、3、2、1依次放入队列中,那么任务出去的顺序是4、3、2、1;

串行队列: 队列中的任务只能一个个执行,前面一个没有执行完,后面一个不能执行;

串行队列

并发队列: 前面一个任务出队列开始执行的时候,后面一个就 可以 在新的线程去执行了,注意这里是可以,表示一种能力,不一定会这样;

并发队列
后面一个任务看到前面一个在开始执行状态就可以出队列,准备开始执行了

3、同步和异步

同步:

异步:

4、一个关于GCD的故事(本故事纯属本人虚构,如果有不恰当的地方待未来改正)

有两个咖啡店,咖啡店1只有一个窗口卖, 咖啡店2有很多窗口卖, 然后两个老师都带着 排着一条长队的 同学去买咖啡, 其中一个老师A告诉她的学生,你们等前面一个买好再接着买,另一个老师B告诉她的学生,你前面的同学开始买选咖啡的时候,下一个就可以去找其他窗口开始买了,不要等的;

5、GCD中的六种组合方式

一. 串行队列 + 同步执行

- (void) GCDTest1
{
    
    dispatch_queue_t queue = dispatch_queue_create("serialQueue.xj.com", DISPATCH_QUEUE_SERIAL);
    
    dispatch_sync(queue, ^{
        
        NSLog(@"1------>>>%@",[NSThread currentThread]);
       
    });
    
    dispatch_sync(queue, ^{
        
        NSLog(@"2------>>>%@",[NSThread currentThread]);
        
    });
    
    dispatch_sync(queue, ^{
        
        NSLog(@"3------>>>%@",[NSThread currentThread]);
       
    });
    
        NSLog(@"4------>>>%@",[NSThread currentThread]);
    
}

结果:

2018-04-01 10:16:17.186574+0800 GCD[55764:12462142] 1------>>><NSThread: 0x604000261c00>{number = 1, name = main}
2018-04-01 10:16:17.186850+0800 GCD[55764:12462142] 2------>>><NSThread: 0x604000261c00>{number = 1, name = main}
2018-04-01 10:16:17.187063+0800 GCD[55764:12462142] 3------>>><NSThread: 0x604000261c00>{number = 1, name = main}
2018-04-01 10:16:17.187228+0800 GCD[55764:12462142] 4------>>><NSThread: 0x604000261c00>{number = 1, name = main}

分析:
这里对应上面故事的第一种情况,由于是同步,不开线程,当前线程为主线程,所以所有任务都在主线程中执行,又因为是串行队列,任务按顺序依次执行,而且还是同步,每次需等block内执行完,所以顺序是1-->2--->3--->4;

二. 串行队列 + 异步执行

- (void) GCDTest2
{
    
    dispatch_queue_t queue = dispatch_queue_create("serialQueue.xj.com", DISPATCH_QUEUE_SERIAL);
    
    dispatch_async(queue, ^{
        
        NSLog(@"1------>>>%@",[NSThread currentThread]);
        
    });
    
    dispatch_async(queue, ^{
        
        NSLog(@"2------>>>%@",[NSThread currentThread]);
        
    });
    
    dispatch_async(queue, ^{
        
        NSLog(@"3------>>>%@",[NSThread currentThread]);
        
    });
    
    NSLog(@"4------>>>%@",[NSThread currentThread]);
    
}

结果:

2018-04-01 10:22:41.780449+0800 GCD[56160:12471344] 4------>>><NSThread: 0x604000079940>{number = 1, name = main}
2018-04-01 10:22:41.780478+0800 GCD[56160:12471596] 1------>>><NSThread: 0x60400027f0c0>{number = 3, name = (null)}
2018-04-01 10:22:41.780803+0800 GCD[56160:12471596] 2------>>><NSThread: 0x60400027f0c0>{number = 3, name = (null)}
2018-04-01 10:22:41.781027+0800 GCD[56160:12471596] 3------>>><NSThread: 0x60400027f0c0>{number = 3, name = (null)}

分析:
因为是异步执行,不会阻塞当前线程,所以先执行4,,开辟了一条新的线程执行1,2,3,然而1,2,3是放到串行队列中的,所以依次然顺序执行1-->2-->3; 这里提一下,既然是异步,为什么不开辟多条线程分别执行1,2,3,没这个必要,既然已经开了一天线程,后面的任务要等前面的执行完再执行,这个线程足以让1,2,3执行任务了,开辟线程是消耗资源的;

三. 并发队列 + 同步执行

- (void) GCDTest3
{
   
   dispatch_queue_t queue =  dispatch_queue_create("xj", DISPATCH_QUEUE_CONCURRENT);;
   
   dispatch_sync(queue, ^{
       
       NSLog(@"1------>>>%@",[NSThread currentThread]);
       
   });
   
   dispatch_sync(queue, ^{
       
       NSLog(@"2------>>>%@",[NSThread currentThread]);
       
   });
   
   dispatch_sync(queue, ^{
       
       NSLog(@"3------>>>%@",[NSThread currentThread]);
       
   });
   
   NSLog(@"4------>>>%@",[NSThread currentThread]);
}

结果

2018-04-01 10:30:24.402362+0800 GCD[56597:12479909] 1------>>><NSThread: 0x60400006f580>{number = 1, name = main}
2018-04-01 10:30:24.432775+0800 GCD[56597:12479909] 2------>>><NSThread: 0x60400006f580>{number = 1, name = main}
2018-04-01 10:30:24.439568+0800 GCD[56597:12479909] 3------>>><NSThread: 0x60400006f580>{number = 1, name = main}
2018-04-01 10:30:24.439568+0800 GCD[56160:12471344] 4------>>><NSThread: 0x604000079940>{number = 1, name = main}

分析:由于是同步执行,所以不会另开线程,阻塞当前线程,所以4是最后执行的,虽然是并发队列可以不用等前面的任务执行完,但是就一条线程,不得不等前面的任务执行完才执行后面的任务,所以1,2,3依次执行;

四. 并发队列 + 异步执行

 - (void) GCDTest4
{
    
    dispatch_queue_t queue =  dispatch_queue_create("xj", DISPATCH_QUEUE_CONCURRENT);;
    
    dispatch_async(queue, ^{
        
        NSLog(@"1------>>>%@",[NSThread currentThread]);
        
    });
    
    dispatch_async(queue, ^{
        
        NSLog(@"2------>>>%@",[NSThread currentThread]);
        
    });
    
    dispatch_async(queue, ^{
        
        NSLog(@"3------>>>%@",[NSThread currentThread]);
        
    });
    
    NSLog(@"4------>>>%@",[NSThread currentThread]);
    
}

结果:

2018-04-01 10:31:14.552817+0800 GCD[56662:12481282] 4------>>><NSThread: 0x604000069640>{number = 1, name = main}
2018-04-01 10:31:14.552818+0800 GCD[56662:12481369] 2------>>><NSThread: 0x6000002742c0>{number = 4, name = (null)}
2018-04-01 10:31:14.552820+0800 GCD[56662:12481372] 3------>>><NSThread: 0x600000274240>{number = 5, name = (null)}
2018-04-01 10:31:14.552838+0800 GCD[56662:12481370] 1------>>><NSThread: 0x604000268a40>{number = 3, name = (null)}

分析:
这是最常用的一种方式,因为它是异步队列,所以它是不会堵塞当前线程的,4会先执行,由于是并发队列,前面的任务开始执行了,后面的任务便可以出队列,异步执行导致为它单独开辟线程执行,所以1,2,3会在不同的线程中执行,如果是1,2,3分别是耗时的操作,那么它们的执行顺序将不得而知,随机;

五. 主队列 + 同步执行

- (void) GCDTest5
{
   NSLog(@"1------>>>%@",[NSThread currentThread]);
   
   dispatch_sync(dispatch_get_main_queue(), ^{
       
       
       NSLog(@"2------>>>%@",[NSThread currentThread]);
       
       
   });
   
   NSLog(@"3------>>>%@",[NSThread currentThread]);
   }

结果:

2018-04-01 10:41:49.864270+0800 GCD[57307:12495333] 1------>>><NSThread: 0x604000664d80>{number = 3, name = (null)}
2018-04-01 10:41:49.868650+0800 GCD[57307:12495215] 2------>>><NSThread: 0x604000261d00>{number = 1, name = main}
2018-04-01 10:41:49.869738+0800 GCD[57307:12495333] 3------>>><NSThread: 0x604000664d80>{number = 3, name = (null)}

分析:
这里不同于上面的点在于,GCDTest5被放在了分线程,那么就好办了,分线程中执行GCDTest5任务时遇到同步,就会一直等,2被放到了主队列,那么2会在所有它前面的主队列中的任务执行完后执行,执行完后分线程中GCDTest5会继续往后执行;

六. 主队列 + 异步执行

- (void) GCDTest6
{
    NSLog(@"1------>>>%@",[NSThread currentThread]);
    
    dispatch_async(dispatch_get_main_queue(), ^{
        
        
        NSLog(@"2------>>>%@",[NSThread currentThread]);
        
        
    });
    
    NSLog(@"3------>>>%@",[NSThread currentThread]);
    
}

结果:

2018-04-01 10:46:06.757861+0800 GCD[57573:12500988] 1------>>><NSThread: 0x60000007f500>{number = 1, name = main}
2018-04-01 10:46:06.758154+0800 GCD[57573:12500988] 3------>>><NSThread: 0x60000007f500>{number = 1, name = main}
2018-04-01 10:46:06.764103+0800 GCD[57573:12500988] 2------>>><NSThread: 0x60000007f500>{number = 1, name = main}

分析:

这个没什么悬念,主队列中的任务是在主线程中执行的,而且主队列是串行队列;

6、线程中的通信方式

7、使用GCD需要注意的地方

8、GCD中的其他重要函数

dispatch_group_t group = dispatch_group_create();
    
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    
    dispatch_group_async(group, queue, ^{
        
        for (int i = 0; i < 3; ++i) {
            [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
            NSLog(@"1---%@",[NSThread currentThread]);      // 打印当前线程
        }
        
    });
   
    dispatch_group_async(group, queue, ^{
        
        for (int i = 0; i < 2; ++i) {
            [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
            NSLog(@"2---%@",[NSThread currentThread]);      // 打印当前线程
        }
        
    });
   
    dispatch_group_notify(group, queue, ^{
        
        NSLog(@"---所有任务完成了--->>");
        
        
    });
上一篇下一篇

猜你喜欢

热点阅读