线程和同步异步的知识,在我们刚踏入程序这一行业的时候就开始接触了。
但是由于I/O(磁盘读写,网络通信)这种耗时的操作,各个语言都有完整的封装方法,我们并不用去了解其异步过程也能完成大部分功能。所以多数人在工作一两年之后,仍然无法理清他们的关系。
不过它对于我们优化代码,了解底层不可或缺,现在我来盘点一下他们的联系和概念。
一.核与线程的关系
我们平时经常会听到8核、16核处理器,那这里的核与线程有什么关系呢?单核代表一个线程么?
单核可以有多个线程,只是它的多线程通过分时来实现,即把时间分成片,每片处理一个线程,所有的线程循环处理。所以对于单核系统而言,开多少个线程都无法提高程序的运行效率。
而多核可以同时实现多线程。比如双核系统开两个线程,运行效率将会翻倍。但并不代表效率可以无限提升,多线程个数等于核的个数时,效率达到最高。
比较另类的是,之前Intel有过16核32线程的机器,它的原理是超线程技术使一个核心能模拟2个逻辑核心,但据说并不能真正达到两个核的水平。
打个形象的比喻:(每种动作代表一个线程)
单核单线程:一个人喝完酒,然后抽烟,最后吃烧鸭
单核多线程:一个人喝一口酒,抽一口烟,吃一口烤鸭,同时进行
多喝多线程:三个人,一个人喝酒,一个人抽烟,一个人吃烤鸭,互不干扰
二.同步异步、阻塞非阻塞
首先,我们先来谈一下同步异步的概念,我查过很多资料,众说纷纭,每个版本的讲法都不一样,出入很大。但其实了解这些概念是为了让我们更加明确整个底层运作方式,所以我挑了一个比较鲜明的概念供大家参考。
(我们iOS平时说到的同步大意和这里的同步阻塞对等,异步与异步非阻塞对等,但是由于js中存在比较重要的同步非阻塞,所以我在这里拆开来讲)
1、同步(sync):
发出一个功能调用时,在没有得到结果之前,该调用就不返回。
2、异步(async):
与同步相对,调用在发出之后,这个调用就直接返回了,所以没有返回结果。当这个调用完成后,一般通过状态、通知和回调来通知调用者。对于异步调用,调用的返回并不受调用者控制。
对于通知调用者的三种方式,具体如下:
状态:即监听被调用者的状态(轮询),调用者需要每隔一定时间检查一次,效率会很低。
通知:当被调用者执行完成后,发出通知告知调用者,无需消耗太多性能。
回调:与通知类似,当被调用者执行完成后,会调用调用者提供的回调函数。
3、阻塞(block):
阻塞调用是指调用结果返回(或者收到通知)之前,当前线程会被挂起,即不继续执行后续操作。
简单来说,等前一件做完了才能做下一件事。
4、非阻塞(non-block):
非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。
总结:所以所谓同步异步,是对于被调用者而言的;而阻塞非阻塞,则是对调用者而言的。
和刚才一样,打个比喻加深理解:
1、同步阻塞:你打电话给114查路线,在不挂断的情况下,客服帮你查了十分钟之后告诉你,期间你一直在接听电话。
2、同步非阻塞:你打电话给114查路线,在不挂断的情况下,客服帮你查了十分钟之后告诉你,你期间吃了个🍉(打电话没有影响你做其他事,显示运用中也很难遇到)。
3、异步非阻塞:你打电话给114查路线,客服说查好之后打给你,这期间你可以做任何事。
4、异步阻塞:你打电话给114查路线,客服说查好之后打给你,但这期间你什么都没做,等到回复电话之后,再继续下一步动作。(是不是很傻)现实运用中,异步阻塞是没有意义的!
三.线程与同步异步的关系
单线程可以异步操作么?当然可以。比如延迟方法,就是典型的异步。
但是单线程异步和多线程异步还是有区别的,因为单线程异步操作在通知调用者之前,是没有跑任何的代码的,因为没有任何的线程提供给它。
其实由于各方概念的差异,也可以说单线程不能进行异步操作,所谓延迟方法,不过是过一段时间之后,把执行函数加入主队列之中,两种说法都存在。
老规矩,打比方(这里的同步异步代表同步阻塞和异步非阻塞)
1、单线程同步:甲先搬了一块砖,回头又搬了另一块砖
2、多线程同步:甲先搬了一块砖,乙又搬了一块砖(要用到线程间的同步机制)
3、多线程异步:甲乙同时各搬了一块砖
四.js的坑,既然名义上是单线程的,却为何能进行真正意义上异步操作
nodeJS编程模式:http://www.cnblogs.com/wwicked/articles/4770416.html
知乎详细链接:https://www.zhihu.com/question/20866267
JS的单线程是指一个浏览器进程中只有一个JS的执行线程,同一时刻内只会有一段代码在执行(你可以使用IE的标签式浏览试试看效果,这时打开的多个页面使用的都是同一个JS执行线程,如果其中一个页面在执行一个运算量较大的function时,其他窗口的JS就会停止工作)。
而异步机制是浏览器的两个或以上常驻线程共同完成的,例如异步请求是由两个常驻线程:JS执行线程和事件触发线程共同完成的,JS的执行线程发起异步请求(这时浏览器会开一条新的HTTP请求线程来执行请求,这时JS的任务已完成,继续执行线程队列中剩下的其他任务),然后在未来的某一时刻事件触发线程监视到之前的发起的HTTP请求已完成,它就会把完成事件插入到JS执行队列的尾部等待JS处理。又例如定时触发(settimeout和setinterval)是由浏览器的定时器线程执行的定时计数,然后在定时时间把定时处理函数的执行请求插入到JS执行队列的尾端(所以用这两个函数的时候,实际的执行时间是大于或等于指定时间的,不保证能准确定时的)。
所以,所谓的JS的单线程和异步更多的应该是属于浏览器的行为,他们之间没有冲突,更不是同一种事物,没有什么区别不区别的。
五.ios的多线程问题
做iOS 的应该都有一个体会,总觉得block是异步的,其实这是错误的理解。
block的线程和它的实现方法处的线程一致,所以我们在调用时,可以检查一下它的实现代码。
我们平时经常讨论的同步问题多发生在多线程环境中的数据共享问题,当多个线程同时操作一个对象时,会出现意想不到的bug,所以这时应该加上线程锁。
这篇文章总结了多篇博客,但却没有完全照抄,加入了很多自己的理解,希望大家多多支持。
网友评论