并发编程gcd粗暴记忆法

这两天撸了撸多线程,对苹果的这套c语言框架gcd很感兴趣,索性撸下去,发现撸的时候很多概念傻傻分不清楚,鉴于我这跟鱼一样的记忆力,要记忆一下

1.最先接触的概念肯定是进程和线程,what?进程和线程还需要记忆,那么别搞it了,不过还是要阐述一下,进程就像一个个运行着的程序,线程就是程序内部代码的执行路线,如果程序中有多个代码的执行路线,那么就涉及多线程了。

2.操作队列,搞这么个东西很容易让人误解为队列就是线程,但是其实不是,这个玩意只是一个队列(FIFO),队列里面放的是任务,也就是代码。

3.主队列,主队列并没有什么神奇,它也是操作队列,只不过它是由系统创建的队列,是类似串行队列,优先级很高

全局队列,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);,与并行队列类似,但是无法确定是哪个队列。

4.同步任务,同步任务的优先级高,并且在同一个队列中有执行顺序,必须等同步任务执行完了才会执行后续的任务,有可能会阻塞线程。

5.异步任务,异步任务的优先级低,等系统比较闲了没什么事做的时候就会执行它,在队列中没有执行顺序,不会阻塞线程。

6.串行队列,这个串行队列,本质上也是队列,加上“串行”二字,就说明串行队列要像电路中串并联的串联一样,任务要一个挨一个的执行,不管你这个任务是异步的还是同步的。

7.并行队列,本质也是队列,加上“并行”二字,就说明并行队列像并联电路一样,任务可以(同时)执行,这里的同时并非真正意义上的同时,具体的解释在操作系统里面的cpu工作方式上有阐述,我们只要关心它类似“同时”,可以达到“同时”执行的效果就可以了。

那么问题来了,队列与任务的组合关系:

1.串行 + 同步

串行队列中的任务是一个挨一个执行,同步任务也是有执行顺序,也要一个挨一个执行,所以得出的结论是,串行队列中的同步任务要一个挨一个执行

dispatch_queue_t q1 = dispatch_queue_create("串行队列", DISPATCH_QUEUE_SERIAL);

dispatch_sync(q1, ^{

[NSThread sleepForTimeInterval:5];

NSLog(@"串行队列同步任务1 %@",[NSThread currentThread]);

});

dispatch_sync(q1, ^{

NSLog(@"串行队列同步任务2 %@",[NSThread currentThread]);

});

dispatch_sync(q1, ^{

NSLog(@"串行队列同步任务3 %@",[NSThread currentThread]);

});

打印结果:

2014-12-09 17:43:55.991 多线程test[4696:942016] 串行队列同步任务1 <NSThread: 0x7fac3bc24860>{number = 1, name = main}

2014-12-09 17:43:55.992 多线程test[4696:942016] 串行队列同步任务2 <NSThread: 0x7fac3bc24860>{number = 1, name = main}

2014-12-09 17:43:55.992 多线程test[4696:942016] 串行队列同步任务3 <NSThread: 0x7fac3bc24860>{number = 1, name = main}

很容易发现问题,串行队列中的同步任务会自动加入到主线程中,并且会阻塞主线程,任务完成后才会更新UI

2.串行 + 异步

串行队列任务要一个挨一个执行,异步任务无顺序,这两个组合在一起,要遵循队列的规则,也就是说,不管你是同步还是异步,需要遵守队列的规则,所以任务也是要一个挨一个有顺序执行。

dispatch_queue_t q1 = dispatch_queue_create("串行队列", DISPATCH_QUEUE_SERIAL);

dispatch_async(q1, ^{

[NSThread sleepForTimeInterval:5];

NSLog(@"串行队列异步任务1 %@",[NSThread currentThread]);

});

dispatch_async(q1, ^{

NSLog(@"串行队列异步任务2 %@",[NSThread currentThread]);

});

dispatch_async(q1, ^{

NSLog(@"串行队列异步任务3 %@",[NSThread currentThread]);

});

打印结果:

2014-12-09 17:49:54.906 多线程test[4834:957312] 串行队列异步任务1 <NSThread: 0x7fa35bd13750>{number = 2, name = (null)}

2014-12-09 17:49:54.907 多线程test[4834:957312] 串行队列异步任务2 <NSThread: 0x7fa35bd13750>{number = 2, name = (null)}

2014-12-09 17:49:54.907 多线程test[4834:957312] 串行队列异步任务3 <NSThread: 0x7fa35bd13750>{number = 2, name = (null)}

很容易看出问题,串行队列的异步任务确实也是按顺序执行的,但是它不会进入主线程中,不会阻塞主线程,先更新UI,后显示结果。

3.串行 + 同步 + 异步

dispatch_queue_t q1 = dispatch_queue_create("串行队列", DISPATCH_QUEUE_SERIAL);

dispatch_async(q1, ^{

NSLog(@"串行队列异步任务1 %@",[NSThread currentThread]);

});

dispatch_sync(q1, ^{

[NSThread sleepForTimeInterval:5];

NSLog(@"串行队列同步任务2 %@",[NSThread currentThread]);

});

dispatch_async(q1, ^{

NSLog(@"串行队列异步任务3 %@",[NSThread currentThread]);

});

打印结果:

2014-12-09 17:56:56.339 多线程test[5117:972472] 串行队列异步任务1 <NSThread: 0x7fc4217564f0>{number = 2, name = (null)}

2014-12-09 17:57:01.342 多线程test[5117:972174] 串行队列同步任务2 <NSThread: 0x7fc421416db0>{number = 1, name = main}

2014-12-09 17:57:01.342 多线程test[5117:972472] 串行队列异步任务3 <NSThread: 0x7fc4217564f0>{number = 2, name = (null)}

很容易发现问题,有异步有同步,还是要遵守串行队列的任务顺序来执行,但是执行到同步任务时依然会加入到主线程,并且阻塞主线程,影响UI显示。

4. 串行 + 同步(嵌套异步)

dispatch_queue_t q1 = dispatch_queue_create("串行队列", DISPATCH_QUEUE_SERIAL);

dispatch_sync(q1, ^{

NSLog(@"串行队列同步任务1 %@",[NSThread currentThread]);

[NSThread sleepForTimeInterval:5];

dispatch_async(q1, ^{

NSLog(@"串行队列异步任务2 %@",[NSThread currentThread]);

});

});

打印结果:

2014-12-09 18:01:12.259 多线程test[5276:982408] 串行队列同步任务1 <NSThread: 0x7fa56a516280>{number = 1, name = main}

2014-12-09 18:01:17.262 多线程test[5276:982631] 串行队列异步任务2 <NSThread: 0x7fa56a712aa0>{number = 2, name = (null)}

很容易看出问题,任务仍然顺序执行,正常。

5.串行 + 异步(嵌套同步)

dispatch_queue_t q1 = dispatch_queue_create("串行队列", DISPATCH_QUEUE_SERIAL);

dispatch_async(q1, ^{

NSLog(@"串行队列异步任务1 %@",[NSThread currentThread]);

dispatch_sync(q1, ^{

NSLog(@"串行队列同步任务2 %@",[NSThread currentThread]);

});

});

打印结果:

2014-12-09 18:04:03.168 多线程test[5389:990941] 串行队列异步任务1 <NSThread: 0x7fa399599d40>{number = 2, name = (null)}

问题来了,任务2没有执行,结果并不是我粘贴少了,程序确实执行到这里就阻塞住不再执行了,下面我们来分析一下原因

串行队列需要按照顺序执行,那么任务1要先执行完,才可以执行任务2,但是任务1里面又有一个同步的任务2,同步任务不会开辟新线程,会自动加入主线程,这样任务2永远都无法执行到,任务2不执行任务1就永远不会结束,任务1不结束,任务2就不会执行.....(开启唐三藏模式)

6.主队列 + 同步

dispatch_queue_t q = dispatch_get_main_queue();

dispatch_sync(q, ^{

NSLog(@"主队列同步任务1 %@",[NSThread currentThread]);

});

打印结果无

主队列是一个运行循环,如果加入同步任务,会造成主队列阻塞,程序会锁死,(再次开启唐三藏模式),运行循环不结束,不执行同步任务,同步任务不执行,运行循环不结束...。

7.主队列 + 异步

dispatch_queue_t q = dispatch_get_main_queue();

dispatch_async(q, ^{

NSLog(@"主队列异步任务1 %@",[NSThread currentThread]);

});

dispatch_async(q, ^{

NSLog(@"主队列异步任务2 %@",[NSThread currentThread]);

});

dispatch_async(q, ^{

NSLog(@"主队列异步任务3 %@",[NSThread currentThread]);

});

打印结果:

2014-12-10 13:34:13.427 多线程test[1570:369316] 主队列异步任务1 <NSThread: 0x7fc9a2611fc0>{number = 1, name = main}

2014-12-10 13:34:13.427 多线程test[1570:369316] 主队列异步任务2 <NSThread: 0x7fc9a2611fc0>{number = 1, name = main}

2014-12-10 13:34:13.428 多线程test[1570:369316] 主队列异步任务3 <NSThread: 0x7fc9a2611fc0>{number = 1, name = main}

主队列的异步任务等同于同步任务,异步和同步是针对主线程来说的,那么在主线程上跑的任务肯定都是有顺序的。

8.并行 + 同步

dispatch_queue_t q = dispatch_queue_create("并行队列", DISPATCH_QUEUE_CONCURRENT);

dispatch_sync(q, ^{

NSLog(@"并行队列同步任务1 %@",[NSThread currentThread]);

});

dispatch_sync(q, ^{

NSLog(@"并行队列同步任务2 %@",[NSThread currentThread]);

});

dispatch_sync(q, ^{

NSLog(@"并行队列同步任务3 %@",[NSThread currentThread]);

});

打印结果:

2014-12-10 13:38:51.408 多线程test[1709:378774] 并行队列同步任务1 <NSThread: 0x7fb7ca516520>{number = 1, name = main}

2014-12-10 13:38:51.409 多线程test[1709:378774] 并行队列同步任务2 <NSThread: 0x7fb7ca516520>{number = 1, name = main}

2014-12-10 13:38:51.409 多线程test[1709:378774] 并行队列同步任务3 <NSThread: 0x7fb7ca516520>{number = 1, name = main}

按顺序执行。

9. 并行 + 异步

dispatch_queue_t q = dispatch_queue_create("并行队列", DISPATCH_QUEUE_CONCURRENT);

dispatch_async(q, ^{

NSLog(@"并行队列异步任务1 %@",[NSThread currentThread]);

});

dispatch_async(q, ^{

NSLog(@"并行队列异步任务2 %@",[NSThread currentThread]);

});

dispatch_async(q, ^{

NSLog(@"并行队列异步任务3 %@",[NSThread currentThread]);

});

打印结果:

2014-12-10 13:40:52.680 多线程test[1754:384474] 并行队列异步任务1 <NSThread: 0x7fe9087034f0>{number = 4, name = (null)}

2014-12-10 13:40:52.680 多线程test[1754:384476] 并行队列异步任务3 <NSThread: 0x7fe90863c660>{number = 3, name = (null)}

2014-12-10 13:40:52.680 多线程test[1754:384475] 并行队列异步任务2 <NSThread: 0x7fe9084792a0>{number = 2, name = (null)}

开启多个线程,任务无顺序,并发执行

10.并行 + 同步(嵌套异步)

dispatch_queue_t q = dispatch_queue_create("并行队列", DISPATCH_QUEUE_CONCURRENT);

dispatch_sync(q, ^{

NSLog(@"并行队列同步任务1 %@",[NSThread currentThread]);

dispatch_async(q, ^{

NSLog(@"并行队列异步任务2 %@",[NSThread currentThread]);

});

});

打印结果:

2014-12-10 13:43:34.638 多线程test[1831:391846] 并行队列同步任务1 <NSThread: 0x7fddd3d281f0>{number = 1, name = main}

2014-12-10 13:43:34.639 多线程test[1831:391864] 并行队列异步任务2 <NSThread: 0x7fddd3c0a4e0>{number = 2, name = (null)}

并发执行。

11.并发 + 异步(嵌套同步)

dispatch_queue_t q = dispatch_queue_create("并行队列", DISPATCH_QUEUE_CONCURRENT);

dispatch_async(q, ^{

NSLog(@"并行队列异步任务1 %@",[NSThread currentThread]);

dispatch_sync(q, ^{

NSLog(@"并行队列同步任务2 %@",[NSThread currentThread]);

});

dispatch_sync(q, ^{

NSLog(@"并行队列同步任务3 %@",[NSThread currentThread]);

});

dispatch_sync(q, ^{

NSLog(@"并行队列同步任务4 %@",[NSThread currentThread]);

});

dispatch_sync(q, ^{

NSLog(@"并行队列同步任务5 %@",[NSThread currentThread]);

});

dispatch_sync(q, ^{

NSLog(@"并行队列同步任务6 %@",[NSThread currentThread]);

});

});

打印结果:

2014-12-10 13:51:42.396 多线程test[2409:421421] 并行队列异步任务1 <NSThread: 0x7f9cebf0dab0>{number = 2, name = (null)}

2014-12-10 13:51:42.396 多线程test[2409:421421] 并行队列同步任务2 <NSThread: 0x7f9cebf0dab0>{number = 2, name = (null)}

2014-12-10 13:51:42.396 多线程test[2409:421421] 并行队列同步任务3 <NSThread: 0x7f9cebf0dab0>{number = 2, name = (null)}

2014-12-10 13:51:42.396 多线程test[2409:421421] 并行队列同步任务4 <NSThread: 0x7f9cebf0dab0>{number = 2, name = (null)}

2014-12-10 13:51:42.397 多线程test[2409:421421] 并行队列同步任务5 <NSThread: 0x7f9cebf0dab0>{number = 2, name = (null)}

2014-12-10 13:51:42.397 多线程test[2409:421421] 并行队列同步任务6 <NSThread: 0x7f9cebf0dab0>{number = 2, name = (null)}

并行队列 + A异步任务 (嵌套B同步) 这时B同步任务会和父任务也就是A任务同步到同一个线程上去。(经过这个研究可以证明,所有在主队列中的任务都会加到主线程,异步任务是在cpu空闲的时候执行,任务默认都不会开新线程,只有串行队列加异步会开1个线程、并行加异步会开n个线程、全局加异步会加n个线程)

全局同并发...

总结出暴力记忆法,这里面主要要理解好,队列,线程,同步,异步的概念。

暴力记忆法:主队列任务都在主线程,性质同串行。

异步任务等cpu空闲执行。

      任务不会开线程,串行加异步开一个线程,并行加异步开n个线程,全局同并行。

      串行加任意任务嵌套同步任务会死锁,其他队列不执行,主队列阻塞程序。

摘抄网友的一些解释,觉得很到位:

ios三种多线程技术:

  1.NSThread

    (1)使用NSThread对象建立一个线程非常方便

    (2)但是!要使用NSThread管理多个线程非常困难,不推荐使用

    (3)技巧!使用[NSThread currentThread]跟踪任务所在线程,适用于这三种技术

  2.NSOperation/NSOperationQueue

    (1)是使用GCD实现的一套Objective-C的API

    (2)是面向对象的线程技术

    (3)提供了一些在GCD中不容易实现的特性,如:限制最大并发数量、操作之间的依赖关系

  3.GCD —— Grand Central Dispatch

    (1)是基于C语言的底层API

    (2)用Block定义任务,使用起来非常灵活便捷

    (3)提供了更多的控制能力以及操作队列中所不能使用的底层函数

1---- 队列和线程的区别:

队列:是管理线程的,相当于线程池,能管理线程什么时候执行。

队列分为串行队列和并行队列等

串行队列:队列中的线程按顺序执行(不会同时执行)

并行队列:队列中的线程会并发执行,可能会有一个疑问,队列不是先进先出吗,如果后面的任务执行完了,怎么出去的了。这里需要强调下,任务执行完毕了,不一定出队列。只有前面的任务执行完了,才会出队列。

2----- 主线程队列和GCD创建的队列也是有区别的。

主线程队列和GCD创建的队列是不同的。在GCD中创建的队列优先级没有主队列高,所以在GCD中的串行队列开启同步任务里面没有嵌套任务是不会阻塞主线程,只有一种可能导致死锁,就是串行队列里,嵌套开启任务,有可能会导致死锁。

主线程队列中不能开启同步,会阻塞主线程。只能开启异步任务,开启异步任务也不会开启新的线程,只是降低异步任务的优先级,让cpu空闲的时候才去调用。而同步任务,会抢占主线程的资源,会造成死锁。

3----- 线程:里面有非常多的任务(同步,异步)

同步与异步的区别:

同步任务优先级高,在线程中有执行顺序,不会开启新的线程。

异步任务优先级低,在线程中执行没有顺序,看cpu闲不闲。在主队列中不会开启新的线程,其他队列会开启新的线程。

4----主线程队列注意:

下面代码执行顺序

1111

2222

主队列异步 <NSThread: 0x8e12690>{name = (null), num = 1}

在主队列开启异步任务,不会开启新的线程而是依然在主线程中执行代码块中的代码。为什么不会阻塞线程?

> 主队列开启异步任务,虽然不会开启新的线程,但是他会把异步任务降低优先级,等闲着的时候,就会在主线程上执行异步任务。

在主队列开启同步任务,为什么会阻塞线程?

> 在主队列开启同步任务,因为主队列是串行队列,里面的线程是有顺序的,先执行完一个线程才执行下一个线程,而主队列始终就只有一个主线程,主线程是不会执行完毕的,因为他是无限循环的,除非关闭应用程序。因此在主线程开启一个同步任务,同步任务会想抢占执行的资源,而主线程任务一直在执行某些操作,不肯放手。两个的优先级都很高,最终导致死锁,阻塞线程了。

时间: 2024-08-10 18:18:27

并发编程gcd粗暴记忆法的相关文章

iOS学习——并发编程GCD

在iOS中使用的多线程技术有四种,Pthread.NSThread.GCD.NSOperation,但GCD与OP严格来说,应该叫并发编程技术.GCD虽然是用C语言书写,但是苹果对它做了很多封装,让它使用起来及其简单方便,因此在OC开发中应用很广.而OP则是在iOS4.0之后对GCD进行了一次封装,增加了许多用GCD实现比较麻烦的功能,如最大并发数,线程暂停,取消以及依赖添加. GCD的使用其实可以拆分成两步,一是队列,二是任务/指令:队列分为串行队列.并发队列.全局队列以及主队列,其中主队列只

iOS并发编程对比总结,NSThread,NSOperation,GCD - iOS

1. 多线程概念 进程 正在进行中的程序被称为进程,负责程序运行的内存分配 每一个进程都有自己独立的虚拟内存空间 线程 线程是进程中一个独立的执行路径(控制单元) 一个进程中至少包含一条线程,即主线程 可以将耗时的执行路径(如:网络请求)放在其他线程中执行 创建线程的目的就是为了开启一条新的执行路径,运行指定的代码,与主线程中的代码实现同时运行 1.1 多任务系统调度示意图 说明:每个应用程序由操作系统分配的短暂的时间片(Timeslice)轮流使用CPU,由于CPU对每个时间片的处理速度非常快

iOS并发编程笔记,包含GCD,Operation Queues,Run Loops,如何在后台绘制UI,后台I/O处理,最佳安全实践避免互斥锁死锁优先级反转等,以及如何使用GCD监视进程文件文件夹,并发测试的方案等

iOS并发编程笔记,包含GCD,Operation Queues,Run Loops,如何在后台绘制UI,后台I/O处理,最佳安全实践避免互斥锁死锁优先级反转等,以及如何使用GCD监视进程文件文件夹,并发测试的方案等 线程 使用Instruments的CPU strategy view查看代码如何在多核CPU中执行.创建线程可以使用POSIX 线程API,或者NSThread(封装POSIX 线程API).下面是并发4个线程在一百万个数字中找最小值和最大值的pthread例子: #import

day10-python并发编程之多线程协程及MySQL

第1章 python并发编程之多线程 1.1 死锁现象与递归锁 1.1.1 死锁概念 进程也有死锁与递归锁,在进程那里忘记说了,放到这里一切说了额 所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去.此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程,如下就是死锁 1.1.2 博客实例 from threading import Thread,Lock import time mutexA=L

并发编程(一)

并发编程(一)    >>>思维导图>>>博客园 操作系统的作用 1:隐藏丑陋复杂的硬件接口,提供良好的抽象接口 2:管理.调度进程,并且将多个进程对硬件的竞争变得有序 多道技术 1.空间上的复用:多个赓续公用一套计算机硬件 2.时间上的复用:切换+保存状态 >1.当一个程序遇到IO操作 操作系统会剥夺该程序的cpu执行权限(提高了cpu的利用率 并且也不影响程序的执行效率) >2.当一个程序长时间占用cpu 操作系统也会剥夺该程序的cpu执行权限(降低了程

网络编程与并发编程总结

目录 软件开发架构: C/S架构: B/S架构: 一.网络编程: 1.互联网协议OSI七层协议 2.socket 3.手撸socket套接字模板 4.subprocess(了解) 5.粘包问题 6.struct解决粘包问题 7.上传大文件数据 8.socketserver(现阶段,了解) 二.并发编程 1.并发与并行: 2.进程调度: 3.进程的三个状态: 4.同步与异步: 5.阻塞与非阻塞 7.回收进程的两种条件: 9.互斥锁: 10.队列 11.线程 12.全局解释器锁 14.递归锁 15.

超强图文|并发编程【等待/通知机制】就是这个feel~

你有一个思想,我有一个思想,我们交换后,一个人就有两个思想 If you can NOT explain it simply, you do NOT understand it well enough 现陆续将Demo代码和技术文章整理在一起 Github实践精选 ,方便大家阅读查看,本文同样收录在此,觉得不错,还请Star 并发编程为什么会有等待通知机制 上一篇文章说明了 Java并发死锁解决思路 , 解决死锁的思路之一就是 破坏请求和保持条件, 所有柜员都要通过唯一的账本管理员一次性拿到所有

关于Java并发编程的总结和思考

编写优质的并发代码是一件难度极高的事情.Java语言从第一版本开始内置了对多线程的支持,这一点在当年是非常了不起的,但是当我们对并发编程有了更深刻的认识和更多的实践后,实现并发编程就有了更多的方案和更好的选择.本文是对并发编程的一点总结和思考,同时也分享了Java5以后的版本中如何编写并发代码的一点点经验. 为什么需要并发 ??并发其实是一种解耦合的策略,它帮助我们把做什么(目标)和什么时候做(时机)分开.这样做可以明显改进应用程序的吞吐量(获得更多的CPU调度时间)和结构(程序有多个部分在协同

知其然亦知其所以然--NSOperation并发编程 (转)

本文是投稿文章,作者:RyanJIN(简书)对于iOS的并发编程, 用的最普遍的就是GCD了, GCD结合Block可以so easy的实现多线程并发编程. 但如果你看一些诸如AFNetworking, SDWebImage的源码, 你会发现它们使用的都是NSOperation, 纳尼? 难道NSOperation这货更屌? YES, 它确实更屌! Okay, 那我们就先来简单PK下GCD和NSOperation(当然这里也包括NSOperationQueue). 1). NSOperation