GCD的队列有两种,一种是串行队列,一种是并发队列。
并行与并发的区别
并发(concurrency)
![](https://img.haomeiwen.com/i1657794/4549cdd052ed3262.png)
1.并发的实质是一个物理CPU(也可以多个物理CPU)在若干道程序(或线程)之间多路复用,并发性是对有限物理资源强制行使多用户共享以提高效率
2.微观角度:所有的并发处理都有排队等候、唤醒、执行等这样的步骤,在微观上他们都是序列被处理的,如果是同一时刻到达的请求(或线程)也会根
据优先级的不同,而先后进入队列排队等候执行。
3.宏观角度:多个线程同时达到的请求(或线程)在宏观上看就像是同时在被处理。
4.通俗点讲,并发就是只有一个CPU资源,程序(或线程)之间要竞争得到执行机会。图中的第一个阶段,在A执行的过程中B、C都不会执行,因为这段时
间内这个CPU资源被A竞争道了,同理,第二个阶段只有B在执行,第三个阶段只有C在执行。其实,并发过程中,A、B、C并不是同时在进行的
(微观角度)。但又是同时进行的(宏观角度)。
并行(parallelism)
![](https://img.haomeiwen.com/i1657794/a34de4b99a3aa496.png)
1.指两个或两个以上事件(或线程)在同一时刻发生,是真正意义上的不同事件或线程在同一时刻,在不同CPU资源上(多核),同时执行。
2.并行,不存在像并发那样竞争、等待的概念。
3.图中,A、B、C都在同时运行(微观、宏观)。
通过多线程实现并发,并行
1.java中的Thread类定义了多线程,通过多线程可以实现并发或并行
2.在CPU比较繁忙,资源不足的时候(开启了很多进程),操作系统只为一个含有多线程的进程分配仅有的CPU资源,这些线程就会为自己尽量多抢时间片,
这就是通过多线程实现并发,线程之间会竞争CPU资源争取执行机会。
3.在CPU资源比较充足的时候,一个进程内的多线程,可以被分配到不同的CPU资源,这就是通过多线程实现并行。
4.至于多线程实现的是并发还是并行?上面所说,所写多线程可能被分配到一个CPU内核中执行,也可能被分配到不同CPU执行,分配过程是操作系统所为,不可人为控制。所以,多线程是并发还是并行的,都有可能。
以上并行
和并发
的原文来自这里
串行队列
任务按队列里的添加先后顺序执行,先进先出(FIFO),前一个任务执行完再开始执行下一个任务。(我们开发中主线程队列就是一个串行队列,所以我们经常在主线程写的一般任务(不考虑多线程),都是顺序执行的)。
注意:一个串行队列里只有一个线程。
1.主队列
dispatch_get_main_queue()
2.自定义队列(串行)
// DISPATCH_QUEUE_SERIAL实际上是指向NULL的宏
dispatch_queue_create("queue_name", DISPATCH_QUEUE_SERIAL)
并发队列
任务会在这个队列中新开线程,并发同时执行(无序)。
GCD使用常伴有dispatch_sync和dispatch_async,这就是同步执行和异步执行。
1.全局队列
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
2.自定义队列
dispatch_queue_create("queue_name", DISPATCH_QUEUE_CONCURRENT)
同步和异步
同步执行:任务都在当前线程中执行,执行过程中会阻塞当前线程。
异步执行:任务会开辟新的线程,并在新的线程中执行,不会阻塞当前线程。
注意
- 同步执行没有开启新线程的能力,所有的任务都只能在当前线程执行。
- 异步执行有开启新线程的能力,但是,有开启新线程的能力,也不一定会利用这种能力,也就是说,异步执行是否开启新线程,需要具体问题具体分析。
- 串行队列中的任务只会放到同一线程中去执行。
- 并发队列中任务会放到不同的线程中去执行。
综上所诉,队列有2种,执行方式有2种,那么他们互相组合会是什么情况呢?
很显然,他们可以组合成4种情况:
- 1)、串行同步队列:任务都在当前线程执行(同步),并且顺序执行(串行);
- 2)、串行异步队列:任务都在开启的新的子线程中执行(异步),并且顺序执行(串行);
- 3)、并发同步队列:任务都在当前线程执行(同步),但是是顺序执行(并没有体现并发的特性)
- 4)、并发异步队列:任务在开启的多个子线程中执行(异步),并且是同时执行的(并发)
![](https://img.haomeiwen.com/i1657794/db0e6257c8ccf201.png)
验证
1.串行同步队列
// 串行同步
dispatch_queue_t queue = dispatch_queue_create("serial", DISPATCH_QUEUE_SERIAL);
dispatch_sync(queue, ^{
NSLog(@"task1");
NSLog(@"task1--%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"task2");
NSLog(@"task2--%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"task3");
NSLog(@"task3--%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"task4");
NSLog(@"task4--%@",[NSThread currentThread]);
});
输出结果:
task1
task1--<NSThread: 0x100602bc0>{number = 1, name = main}
task2
task2--<NSThread: 0x100602bc0>{number = 1, name = main}
task3
task3--<NSThread: 0x100602bc0>{number = 1, name = main}
task4
task4--<NSThread: 0x100602bc0>{number = 1, name = main}
分析:任务是在当前线程(当前是主线程)顺序执行的。这也验证了
串行同步队列:任务都在当前线程执行(同步),并且是顺序执行(串行)
这里需要注意的是代码直接写在viewDidLoad里,主队列也是也一个串行队列,但在主线程中使用主队列同步执行会造成死锁。另外,若在viewDidLoad新开一个子线程,去执行代码,结果是同样可以验证的:
// 开启新线程
[NSThread detachNewThreadWithBlock:^{
// 串行同步
dispatch_queue_t queue = dispatch_queue_create("serial", DISPATCH_QUEUE_SERIAL);
dispatch_sync(queue, ^{
NSLog(@"task1");
NSLog(@"task1--%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"task2");
NSLog(@"task2--%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"task3");
NSLog(@"task3--%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"task4");
NSLog(@"task4--%@",[NSThread currentThread]);
});
}];
// 输出结果:
task1
task1--<NSThread: 0x1028004b0>{number = 2, name = (null)}
task2
task2--<NSThread: 0x1028004b0>{number = 2, name = (null)}
task3
task3--<NSThread: 0x1028004b0>{number = 2, name = (null)}
task4
task4--<NSThread: 0x1028004b0>{number = 2, name = (null)}
死锁情况:
dispatch_sync(dispatch_get_main_queue(), ^{// 在主队列里执行同步操作会死锁
NSLog(@"task1");
NSLog(@"task1--%@",[NSThread currentThread]);
});
2.串行异步队列
dispatch_queue_t queue = dispatch_queue_create("serialqueue", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
NSLog(@"task1");
NSLog(@"task1--%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"task2");
NSLog(@"task2--%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"task3");
NSLog(@"task3--%@",[NSThread currentThread]);
});
NSLog(@"task4");
NSLog(@"task4--%@",[NSThread currentThread]);
输出结果:
task4
task1
task1--<NSThread: 0x100582fd0>{number = 2, name = (null)}
task4--<NSThread: 0x100509fa0>{number = 1, name = main}
task2
task2--<NSThread: 0x100582fd0>{number = 2, name = (null)}
task3
task3--<NSThread: 0x100582fd0>{number = 2, name = (null)}
分析:主线程异步调用,我们先分析加到队列里的task任务1、2、3,确实是在开辟了的新线程<NSThread: 0x100582fd0>{number = 2, name = (null)} 上顺序执行的,关于task4,由于是异步的,它也没加入到queue,啥时候输出就看电脑心情了。
验证结果:
串行异步队列:任务都在开启的新的子线程中执行(异步),并且顺序执行(串行)
这里需要注意,由于新创建了串行线程,所以任务会在新开启的线程上执行,若是直接在主队列异步调用,任务执行都在主线程上。
3.并发同步队列
dispatch_queue_t queue = dispatch_queue_create("concurrentqueue", D
dispatch_sync(queue, ^{
NSLog(@"task1");
NSLog(@"task1--%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"task2");
NSLog(@"task2--%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"task3");
NSLog(@"task3--%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"task4");
NSLog(@"task4--%@",[NSThread currentThread]);
});
输出结果:
task1
task1--<NSThread: 0x102a03400>{number = 1, name = main}
task2
task2--<NSThread: 0x102a03400>{number = 1, name = main}
task3
task3--<NSThread: 0x102a03400>{number = 1, name = main}
task4
task4--<NSThread: 0x102a03400>{number = 1, name = main}
分析:任务是当前线程(是主线程没有开辟新线程)顺序执行的,跟串行同步一样,虽是并发队列,却不能并发。得到验证结果:
并发同步队列:任务都在当前线程执行(同步),但是是顺序执行的(并没有体现并发的特性)
4.并发异步队列
//并发异步队列
dispatch_queue_t queue = dispatch_queue_create("concurrentqueue",DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"task1");
NSLog(@"task1--%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"task2");
NSLog(@"task2--%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"task3");
NSLog(@"task3--%@",[NSThread currentThread]);
});
NSLog(@"task4");
NSLog(@"task4--%@",[NSThread currentThread]);
输出结果:
task4
task1
task2
task3
task2--<NSThread: 0x1030055a0>{number = 2, name = (null)}
task4--<NSThread: 0x100507190>{number = 1, name = main}
task3--<NSThread: 0x100406450>{number = 3, name = (null)}
task1--<NSThread: 0x103200000>{number = 4, name = (null)}
分析:先看task4吧,没有加入队列,所以肯定是在主线程执行的,由于异步,啥时候执行还是要看电脑执行……我们看加入到并发队列里的任务1、2、3,在不同的线程中无序执行,每个任务都开辟了新的线程去执行,并且执行顺序是无序的,体现了并发的特性。所以我们经常也是使用这种方式做一些需求。验证结果:
并发异步队列:任务在开辟的多个子线程中执行(异步),并且是同时执行的(并发)
番外:做个手抄,加深印象,原文请移步这里
网友评论