cloudaice

    异步和非阻塞

    同步和异步

    同步这个词在很多场景下都会出现,例如:我要把我的手机通讯录同步到云端。这个同步指的是要把两个对象中的数据保持一致的意思。实际的操作可能就是上传和下载。另外还有同步卫星,同步直播啊。这些概念都有保持一致或者保持实时的意思。而在程序编码领域,同步在不同地方表达的意思也有点偏差。在操作系统领域,同步表示进程之间的协作。而在web开发领域,同步往往意味着顺序执行,表现的状态就是阻塞。这和进程之间的协作所表达的意思略有不同。同步的反面即为异步,而异步和非阻塞几乎是服务器端开发挂在嘴边的词。据我观察,真正对其内在工作原理进行深入了解的人却不多。我大三的时候接触NodeJS。社区对其口号喊的最响的就是:它是异步的,事件驱动的,函数回调的。当时初入互联网开发的我迷糊了好长一段时间,却找不到最本质的原理。的确照着官方文档画葫芦,谁都会画。但是对原理性的东西懂得多一些,写代码的时候,自己的心里就会有底一些。于是一年多来,不间断地就会关注这方面的话题,渐渐积累了一些知识。记录一下。

    Web服务器

    Web服务器,撇开它对http协议封装这些不谈,我们在这里只是关注它的工作方式。它的工作方式基本是这样子的:来一个连接请求,与其建立一个连接,然后进行相应的数据传输,最后断开连接。假如它是单进程单线程的,那么一个请求过来,成功建立连接之后。在这个请求结束之前,其它请求都没有办法再被处理了。这样明显不行,web服务器本来就是用来给千万网民访问的嘛。

    多进程

    ok,我们使用多进程方式来做。那么来一个请求,我就spawn一个子进程。这样同时有多少连接请求过来。它就会生成多少个进程。这样做的确可以解决处理多个任务的问题。但是当同时过来千万甚至是上亿级别的请求时,要一台计算机启动千万个进程来处理。那简直是天方夜谭。机器的资源早就被耗尽了。

    多线程

    既然瓶颈在资源上,那我们使用线程来替代进程,在操作系统课程中我们学过线程是轻量级的进程,在这里完全可以使用线程来替代进程。这么改进之后,性能的确会有很大的提升。接下来我们观察发现,其实这些线程大多数都是在阻塞态。打个比喻:我们要做一百道菜,于是我们就起了一百个灶,买了一百个锅,开始干了。于是有的开始去买菜,有的开始洗菜,有的开始炒菜,而事实上,在每一个时刻,有很多灶都空着。根本没有用到。这里面有很大的优化空间。

    事件模型

    ok,事件驱动模型就出现了,目前的nginx服务器就是这个模型。事件驱动这个词一开始我觉得不太好理解。其实它的原理很简单,就是先注册一个事件,然后这个事件发生了,就来通知你,告诉你可以干活了。原理说的很轻巧,但是在计算机中是怎么实现的呢?其实在计算机的世界里,你接触的越深,越会发现站在巨人的肩膀上这句话是多么的适用。是的,nginx作者也不是从底层硬件开发出这么一个事件模型出来的。而是通过操作系统的事件库。目前2.6及以上的linux内核下最常用的事件库就是epoll。还有类BSD系统的kqueue。查看这些系统库的文档,按照要求使用就可以了。我向来喜欢追根问底,epoll又是怎么实现的呢?它是linux内核实现的一个系统调用,其实在它之前还有select, poll等,到后来不断优化到epoll这个系统调用。select的实现原理很简单,就是把一堆注册的事件放在一个事件队列里面,有个进程不断地在看哪个事件生效了。epoll实现原理也是类似,不过在算法上改进很多。更加详细地实现可以Google相关资料进行了解。

    除了各个操作系统自己提供的基于事件编程的系统调用之外,开源大牛们也编写了一些事件编程的库。使用这些库来编程,可以简化编码,还可以跨平台,在各个系统上都可以正常运行。顶顶大名的就是libev。注意,libev和libevent不是一个东西,两者都是事件编程的库,但是libev在性能上要优于libevent,成替代libevent的趋势。

    协程

    在两年前,协程似乎是一个很高级的东西,随后大多数语言或多或少都支持协程。我比较熟悉的有Python的gevent,Lua的coroutine,Go的goroutine。尤其是Lua和Go,语言本身就支持协程。协程也被叫做轻量级线程。通俗点讲就是定义一大堆任务,然后通过一个线程轮着对每个任务都执行一下,协作运行。它的厉害之处在于每运行到一个任务的时候,它都可以从这个任务上一次中断的地方开始运行。在我们一般的印象中,只有操作系统对线程进行调度的时候才会干这样的事情,进行各种进栈,保存状态。而协程,总共也只是运行在一个线程中,要是使用线程本身的系统栈,早就暴了。因此在这里,实现的时候是用内存来模拟栈的操作。具体实现,我想复杂度一定会不小。

    我们知道,线程比进程轻量级,因此产生一个线程消耗的资源比进程少,上下文切换也比进程节约。而协程比线程更加轻量级,上下文切换更是迅速。于是在服务器编程方面给人无限想象。尽管目前还没有出现一款主流的采用协程的web服务器。但是Go语言开发的web服务的性能已经崭露头角了。

    真正的异步

    写到这里,似乎异步和非阻塞的问题也就差不多了。但是在实际使用中,却还有很多疑问。先说一下并发和并行的区别。

    并发和并行

    而在web开发上遇到的模型,绝大多数都是并发。也就是说,往往瓶颈不是在计算资源上,而是在I/O。这里的I/O包括磁盘I/O和网络I/O。在上面,我主要讨论了web服务器在处理并发情况下的应用手段。目前采用比较普遍的是事件模型。上面事件模型处理的事情有一个共同的特点,全都是对socket事件进行操作。而新的问题恰恰出现在这里。这些事件库并不支持对regular file的非阻塞操作。因此,当我们要对文件进行操作的时候,只能被阻塞了。而NodeJS作者在实现Node的时候采用了这样的方法

    node事件库

    uv库作为对libeio和libev的一个封装,为上层提供调用接口,socket fileregular file的非阻塞操作由libev和libeio来实现。那么libeio是怎么实现对regular file操作的非阻塞的呢?很简单,线程池+同步模拟。当然内部实现方式仁者见仁,智者见智。我也没有去仔细研究它的源代码。

    在讨论异步非阻塞的时候,大多时候忽略了对regular file操作的非阻塞。Node在语言层面上就实现了异步非阻塞。而Python只是通过事件库等方式来实现异步。amix大牛写了一篇关于non-blocking servers博客。其中就讲到了Tornado服务器。当使用阻塞的依赖库的时候,Tornado这样的WebServer的性能将会大打折扣。

    在这里分析一下为什么即使使用Tornado的异步效果,在使用阻塞的库的时候还是会导致整个进程阻塞。首先要明确单实例Tornado运行的时候是单线程的,那么当访问数据库的时候阻塞10秒钟,这个进程就会被卡住10秒钟,却干不了其它事情。因为Tornado的异步核心在于IOLoop这个模块。而IOLoop是基于事件库实现的,当你访问数据库的时候,使用的是自己的数据库驱动程序,那么Tornado自身带的异步机制根本就没有办法发挥出来,所以会造成阻塞。因此,根据我的理解,要发挥出Tornado的非阻塞功能,只有使用它自带的异步库,或者使用第三方库也是异步的,否则根本不会有效果。

    关于对regular file的AIO,除了libeio这种线程加同步进行模拟的方式,还有其它哪些方式呢?在Linux下有一种原生的AIO,叫Kernel Native AIO。这种AIO有个致命的弱点,就是无法使用操作系统的磁盘访问缓存,Windows倒是有真正的AIO实现:叫做Windows overiapped I/O,算是真正意义上的AIO。另外关于Linux的AIO更多历程,可以看看这篇文章

    总结

    异步非阻塞的实现有很多种方式,多进程,多线程,基于事件库,使用AIO库。但是要明白事件库和AIO库是两个不同的技术实现。在Linux下,事件库主要用来处理socket,管道等。但是它没有办法处理regular file的异步读写。AIO目前在Linux下有glibc aio, libeio等库。它们主要使用线程池进行模拟。而另外的Kernel Native AIO由于只支持O_DIRECT方式对磁盘读写,应用也甚少。

    巴黎之行

    离开克莱蒙费朗

    来到法国的时候,就想着期间一定要去巴黎逛一逛,在我的印象中,巴黎是一个充满着艺术和浪漫🌹的城市。但是对于它的细致的了解却是很少。但是也是带着朦胧的憧憬踏上火车的。很感谢这边的学长帮忙预定火车票和旅店。让我们省去了很多的麻烦事。在离开的前几天,还特地去克莱蒙费朗的火车站研究了一下怎么上火车,最后打印了电子票。貌似这里在上火车的时候不会查票,因此也不用像国内一样要排着长长的队伍。而且只会提前二十分钟告诉你在哪个站台上车。在一个下着小雨的清晨,踏上了去往巴黎的火车。火车上人很少,泛着淡黄色,暖暖的灯光。空阔的车厢内没有多少乘客。

    火车

    巴黎第一天

    到达巴黎已经是中午十二点多了,给人的感觉,好像没有大都市那样的繁华景象

    火车站

    下了火车先是寻找地铁站,然后买了地铁票,根据指示的地铁线路图和GPS导航来到了预定好的旅店。在寻找旅店的途中,我看着google地图的导航,想要穿一条小路,没想到把大家带到了一个公园里面,被围栏围着,于是只能是绕着出去。

    虽然是比较便宜的旅店,但是我对于住宿条件什么的是没有太高的要求的。感觉还是挺好的。随便休息了一下就准备去往第一站:Galeries Lafayette Haussmann

    lafay

    这是一张内景图,一楼刚进去就感觉人山人海。进而发现里面逛的人大部分都是中国人,后来在网上查的时候看到有说那里的80%购物的人群都是中国人。给我一种中国的集市的感觉。但是那里的东西也并不是都很便宜的。不禁感叹国人的钱啊。不过像我们这样的穷学生也就是过来看看热闹,顺着楼梯朝楼上走去。相比于一楼买表,化妆品,楼上买服饰之类的,不过在中间的一个地方有买一种小小的圆饼(后来知道它就是马卡龙)。看着好多人排着队再买,玉同学很快就排上队了,告诉我网上有很多推介的。可怜我孤陋寡闻啊,也难怪,在走之前,我还沉醉在github上多提交一些commit呢。

    马卡龙

    后来,和另外两个同学走散了。我和周同学在买小饰品的地方逛了很久,不知道为什么,每次出去的时候总是想买一些小饰品,但是总有一点不太好,就是你往往会看到made in china的字样。当时在东京也是这样子。后来买了一件印有paris的T恤。最后在lafay比较惊喜的发现是在大楼的顶上有一个宽阔的天台

    lafayette

    站在上面可以眺望半个巴黎。

    半个巴黎

    反正和其他两位同学走散了,于是我和周同学就靠着手机的GPS导航,开始在巴黎乱逛了。在巴黎街头,随便抬头一看就是一件艺术品。圆柱子,圆顶,墙上有各种雕塑品,或许就是哪个艺术家的作品。处处透露着古典和恢宏。

    巴黎歌剧院

    巴黎歌剧院

    歌剧院前的演奏者

    people

    在巴黎,随处可见这样的多岔路口

    road

    跟着导航,径直朝塞纳河的方向走去,中间恰巧经过协和广场

    协和广场

    其实这个时候已经是晚上7点半了,但是天还是很亮。一路过来,完全是按照google地图朝着塞纳河的方向走去的。但是经过的每一个地方都是有那么些的历史掠影的。有时候我更加喜欢这种发现的惊喜,并不是一定要按着事先规划好的路线,然后按部就班的去走。把这一切当作任务似的。当然我这样的随机游走似的逛可能会错过很多。

    终于看到塞纳河

    塞纳河

    沿着塞纳河,迎面吹来习习的凉风,两边是各种欧式的建筑。往往看到一个恢宏的圆顶的建筑,就会认为它应该是某种比较特殊的建筑,但是可惜的是自己也不知道它的内涵。我们沿着河一路走。路过卢浮宫,奥赛博物馆,朝着岛上的巴黎圣母院走去。对于它的印象只是那部小说和电影。其实它是巴黎的很重要的一个教堂。我们到达那里的时候已经是晚上8点多了,正常来说,早已经关门了,但是那天运气很好,刚好碰到里面有管风琴演奏

    巴黎圣母院

    在里面享受了将近一个小时的音乐的洗礼。出来的时候已经是9点了。天也变的有些黑了。路上灯光闪烁。正常是应该做地铁回去的。但是想看看巴黎的夜景,并且手里也有google地图,跟着GPS完全可以走回去。于是决定一起走回去。尽管最近经常有华人在巴黎被抢劫的事件发生。但是两个大男人,觉得也没什么好怕的。巴黎的夜里也算是比较热闹的。路的两边的店面都开着,马路上来来往往的人也很多。经过一家电影院的时候,看电影的人排着长长的队伍,都在路边排了长长的一队。终于在9点50分左右安全到达旅店。从巴黎圣母院走到巴黎十三区的最南边。这一天感觉基本上已经把巴黎比较闻名的地方都逛的差不多了。埃菲尔铁塔和凯旋门只是在协和广场边上远远的望了一眼。

    第二天

    巴黎圣母院-卢浮宫-凯旋门-埃菲尔铁塔

    因为玉和刘两位同学和我们走散了,没有欣赏到圣母院的每秒音乐。所以第一站选择圣母院。周日的圣母院刚好赶上虔诚的信徒们做祷告。我们几个就在里面乱转,圣母院里面有很多雕像和壁画,可能每一件都是珍品,但是对于我这样的艺术盲来说,看起来都差不多,而且也看不出哪样好和哪样不好。只是觉得都是很珍贵。在圣母院的一个角落,发现了一个立方体的玻璃缸,里面投满了各种纸片,写着各样的愿望。桌面上刚好还剩下两张,我和同学一人一张,写下了愿望。奶奶就是信基督教的。小学的时候,经常在星期天去教堂做礼拜。我们过去就是对中饭感兴趣,往往有豆面和肉。然后在耶稣降生日还可以免费吃到大桌的菜。后来才知道那个耶稣降生日就是圣诞节。那天圣母院的活动也和这个类似。有人在上面讲,下面很多人在听。间或会唱几句。只是这里显得更加正式。其实这种形式的宗教信仰也挺好的。至少它在很大程度上给人以心灵上的慰籍和支撑,可以让人在困境中而不放弃希望。

    圣母院

    卢浮宫,这个世界著名的艺术殿堂,对与蒙娜丽莎,没有人会不熟悉,而我之前对它的理解也仅仅在于蒙娜丽莎和维纳斯。

    卢浮宫

    我们用了4到5个小时才草草地将它逛了一下。整个博物馆实在是太大了。而每一件馆藏可能都是无价之宝。

    三宝

    最后一个是胜利女神。还记得高中的时候在语文课上,老师讲到这个雕像出来的时候,因为大家都赞美她的手实在是太美了。作者将她的双臂砍掉了。并以现在的眼光去看,这是一种残缺美,但是我当时并不是这么认为的。一件完整的东西为什么要弄的残缺的呢?当时老师也只是笑笑。不过现在,她仍然吸引着无数的游客观赏。梦娜丽莎就更加不用说了,我挤了好一会儿才挤进去,拍到几张正照。偌大的一面墙就放着她一个,而且还有一面玻璃隔着。最后的胜利女神差点错过。她被放在一个楼道的旁边,瞻仰她的人围成了一圈。

    个人感觉博物馆里面最多的就是各种性感的艺术雕像和绘画品。不过可惜的是自己都无法欣赏其内在含义。不止一次在想,要是有学艺术的来这里参观的话,那该是怎样的一种的兴奋啊!而又想到自己,对于自己而言,一个可以让自己兴奋的地方又在哪里呢?

    梳妆镜

    在卢浮宫逛的累趴了。沿着塞纳河往凯旋门的方向走去。一路上踩着草坪,慢慢悠悠的走着。然后进入香榭丽舍大街,陪同学在一家化妆品店逛了逛,当时我还不知道那就是香榭丽舍大街。来到了凯旋门下面。感觉和中国的大城墙差不多。

    凯旋门

    本来看到网上有人说学生可以在售票的地方买到免费的门票。我们几个也排上了队,可惜遇到一个黑人售票员,告诉我six eruo.心想自己连埃菲尔铁塔都还没上,现在为了上这么点高的地方,先破费了。于是扭头就走了。当时和另外一位同学走散了,大概快九点的样子,天渐渐黑下来,看到远处的埃菲尔铁塔华灯初上。于是大家决定过去逛逛。

    埃菲尔铁塔

    直到走到塔的底下,夜色全部暗了下来。火红色的铁塔倒映在塞纳河上,显得异常美丽。这天我们没有上铁塔,而是在底下转悠了几圈之后便准备回旅店了。在去地铁站的路上发生了一点小意外。在一个地下通道上楼梯的地方,玉同学的书包被小偷拉开了。走在前面的我只听见一声叫声。回头跑到玉同学的身边的时候,身后只见一个中年妇女说着are you ok ?。其实我在上楼梯的时候就感觉到有点不安全,当时差不多是晚上10点了。路边总有黑人卖着廉价的埃菲尔铁塔的挂饰。后来我感觉就跟国内的新疆人卖着羊肉串似的。不过幸好没有东西丢失。最后也平安回到旅店。

    第三天

    圣心教堂-埃菲尔铁塔

    上午我们几个来到蒙马特高地的红磨坊。不过除了一个红色的十字大风车之外,我看不出什么奇特的地方。可能因为是白天的缘故,显得也不怎么热闹,不过倒是有很多的游客在那里拍照。随后就朝圣心大教堂走去,真的是高地啊,我们基本上都是一直在上坡,最后看到几乎在山顶上的圣心大教堂。

    圣心大教堂

    在去往教堂的路上,看到扛着冲锋枪的警察在那里巡逻。果然如学长说的,北区很乱啊。对于圣心教堂,可能是因为到后期基本没有力气的原因,总感觉看过巴黎圣母院之后,其他教堂都只能是其的简单复制罢了。没有什么特别的震撼。下午一点左右,我回旅店叫上玉同学和另外两个同学一起在埃菲尔铁塔下会合。准备一睹铁塔日景和夜景。现在想想其实比较坑的,为了看铁塔夜景,在埃菲尔上整整等了将近4个小时。5点多上塔,直到10点多才下来。而且在塔的其中一面风很大,非常冷。于是就和玉同学在拍一圈就回屋内暖和一下这样的循环中拍摄着巴黎的夜景

    埃菲尔铁塔

    想起八个月前,我站在东京铁塔之上。时间真的很巧,查看当时在东京铁塔上拍的照片的时间,恰好也是29号。八个月之前的晚上我站在东京铁塔之上,八个月后的晚上我却站在埃菲尔铁塔之上。不知道在这样两个不同的时间和不同的地点,是不是会有两个相同的人出现呢?有的时候不得不感叹这个世界的神奇。

    第四天

    凡尔赛

    或许是因为前三天的游荡已经耗费了太多的体力的缘故,这天所有人都感觉有些无力了。凡尔赛相对于其它几个景点来说,离的比较远,比较能够体现这一点是从凡尔赛回来的时候,我们坐的火车是说开往巴黎方向的,换句话说我们已经离开了巴黎。准确的说是巴黎市区。在凡尔赛的外面广场上排队排了将近两个小时。这样的排队长度超过了我们之前的所有的旅游景点的排队长度,而且是在室外排队,天气也是阴沉沉的,风吹的感觉好冷好冷。中间实在饿的受不了了。和玉同学去麦当劳吃了一顿,而貌似那一顿是在巴黎吃的最饱的一顿。回来之后,就已经可以进入凡尔赛宫了,还是依旧的雕像和绘画。不觉感到审美疲劳。而人流也是异常拥挤。越发显得房间比较小。整个人在里面随着人流挤得晕晕的。貌似真的没有流连的意愿。后来玉同学独自从一个封锁住的楼梯下去,与我们走散了。最后在入口的大门处找到了。在巴黎因为互相之间没有通讯方式而走散过好多次。出了凡尔赛宫,感觉空气清新了好多。走到一处绿色草坪,在上面躺了一小会儿。这样的风景着实让我们悠闲了一把。

    草坪

    在回巴黎的火车站又发生了点小插曲。不知道什么原因,开往巴黎的火车停止运行了。我们只能去旁边的一个火车站坐另一条线路的火车。但是去了之后发现那边人山人海,而且火车也不是正常运行的。要自己听广播和看大屏幕。第一次在法国看到这样多的人在排队等火车。给我一种中国春运的感觉。

    排队

    最后还是跟国内春运挤火车似的挤上了一辆开往巴黎的火车。有一种流浪冒险家的感觉。不过有一点让我感觉比较意外,因为是火车系统出了问题,所以我们到巴黎的火车是免费的。进站不用检查票。回到巴黎的时候外面下起了雨,本来打算去一趟中国超市的,但是这个计划也被取消了。算是我在巴黎回旅店最早的一次。

    第五天

    最后一天了,起床后就收拾东西准备回家了。不过因为火车是下午4点的。上午退了房间之后,我们几个去逛了一下中国超市,然后游游荡荡的朝塞纳河走去,一边逛一边走,最后在卢申堡公园内坐了一个小时就准备去火车站了。中间我跑去想买一些马卡龙。找到谷歌地图上标记的地点,却死活也找不到那家店面。由于是五一,很多店面都关闭了。街上显得也是比较冷清。最后一次在巴黎坐地铁去火车站。

    地铁

    结语

    在巴黎待了5天4夜,但是现在回想起来,印象最深的是前两天。甚至是第一天的一个下午,就把巴黎著名的地方基本都走遍了。巴黎的确是一个艺术之都,在塞纳河边漫走,随处一抬头,看的的都是一件艺术品。它完全不同于其它的大都市,给人以一种现在科技的距离感。给我的感觉唯有那种艺术的深奥和无法理解。但是心中却满是赞叹和仰慕。它的环境并不好,甚至比不上中国的一些大城市。包括塞纳河的水也并不清澈,从桥地下走过,甚至还会闻到一阵阵臭味。街上也可以见到垃圾。这些和它的浓厚的艺术气息结合在一起,给人一种自由的随意感。是的,在这座城市,我感受到了自由。地铁到站,是人自己去打开门的,更加有意思的是,人可以在车还没有停稳的情况下打开门下车。上火车的时候也不会去检查你的票。甚至从上车到出战,你的票都没有派上用场。但是这些自由之下会有隐隐的一些限制,你可以狂妄一些,只要你在遵守规则之内,否则,你可能可以逃过一次两次,但是一旦发现,那么惩罚是很重的。换一个角度思考,相当于这个城市给了你偶尔做做鬼脸的自由,但是你不能天天都做鬼脸。在五天的旅行中,我也无意之中逃过两次地铁票。

    另外关于旅行本身,没有手机卡的我们,沟通真的是一个问题。没有网络,google地图也是一个问题。为什么没有这样的一个应用,它不依赖于手机卡来进行通信交流,而是可以直接通过点对点的设备之间的交流,哪怕是局域之内的。另外google地图的离线功能还不够完善,没有离线搜索和离线签到等等可以通过短暂的离线来实现模拟在线的功能。而且个人认为对于地图这些应用,移动端应该要比PC浏览器端做的更好才对。

    最后,这次巴黎之行,虽然还是匆忙并且还有些遗憾的。但是终究会是记忆碎片中的一叶!