谈谈事件驱动
事件驱动
这个技术方案,可以说实实在在影响了这些年编程界的技术方向。最实际的受用者应该就是异步编程
了,如 I/O。
我所认知到的语言,都是事件驱动的使用者,受益者,推动者。
很多朋友可能更多的停留在精通官方 API 阶段,还没有更深层次的认知计算机原理,不晓得代码是怎么工作的。我不精通官方 API,计算机原理也认知浅薄,但在自己认知的语言范围内了解了一些。我感到庆幸,希望和大家分享。
事件驱动
的形象描述
A 和家人去外婆家取了个号。A 一直在门口等着,是阻塞。A 出去玩一会,门分钟去外婆家门口看看到了自己号没有,是监听。A 去一个衣服店看衣服去了,到了自己号的时候,收到外婆家发的短信消息后直接去外婆家,是回调。
上面这个例子,变种极多也千篇一律。串行并行、同步异步、阻塞非阻塞都可以用。我们用这个例子来说事件驱动
。
这里分析第三种情况,A 去看衣服去了,这个时候外婆家的号叫到自己,并短信通知了自己,这个行为的分析。
A 查看短信的行为和外婆家发出短信的行为,就是我们分析的重点。
外婆家为了发出这个短信,需要耗时,甚至外婆家也不知道耗时多久。所以外婆家需要做的是,一定要在 A 的号到了的时候,准确及时的发出短信,这是一个事件的发出。
A 虽然有手机,但是看不看短信是 A 的事情。所以 A 一定要在看到短信之后立即作出处理判断,这是一个事件的反馈。
但是 A 为了能够尽快吃到饭,多做了几手准备,他把西贝、海底捞几家店的号都拿了,打算谁先叫到自己,就去谁家。
所以 A 接受到的事件是多个并且不确定的。
Life is thread
,我们把 A 比作一个线程。A 能够及时响应各家店面发来的消息,原因就是线程里面有一个 while (true):{pass;}
这样的循环。依靠 CPU 这个超强大脑控制器,只要有事件需要通知到线程,线程里面的这个 while 循环就会获取到并及时处理。
所以事件驱动
的本质是:一方及时发出事件,通过 CPU 时间片实时轮转事件循环队列并告知到 while 循环以通知到另一方,另一方及时响应事件。
iOS 中的使用
Runloop
Runloop
可以说把事件驱动
利用到了极致。你能想象,如果没有 Runloop
,你就真的不能使用 iPhone 手机了!Runloop
依托于线程。我们手势点击一个按钮,就是在操作主线程里的 Runloop
。Runloop
通过事件驱动
在以下 8 种状态下实时循环切换,用于省电的同时又能够及时处理用户界面反馈。
1 | typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) { |
闭包
我们通过 IOS 里的 Block
闭包,可以在异步执行一串功能逻辑代码后接着处理闭包里的活。
1 | - (void)someMethodThatTakesABlock:(returnType (^nullability)(parameterTypes))blockName; |
1 | [someObject someMethodThatTakesABlock:^returnType (parameters) {...}]; |
还有其他非常多的使用,如通知等
Python 中的使用
Python 近些年才完全开发完优秀的协程
并开放使用。使得 Python 上多并发
成为事实上的可能。这里的多,不是之前的几十几百,是上十万。
Event_loop
+ 协程
Python 里面使用多线程其实并不怎么爽,本身就是耗资源的语言,多线程切换更加雪上加霜了。通过协程,妥妥的解决了上十万的并发。
1 | import asyncio |
aiohttp
网络访问上的多并发,对协程
的进一步封装。
Node.js 中的使用
Event_loop
事件循环
这个就没得说了,彻彻底底依靠事件驱动
起家的语言。基于 javascript
和 V8
引擎起来的 Node.js,就是完完全全的单线程语言。
可是要知道,Node.js 就是以单线程中使用事件驱动处理高 IO 闻名世界的。
你可以想象一下,一个 Node.js 搭建的后台,每秒上千上万的并发,都是单线程在处理吗?
Java 就是一个用户一个请求一个线程(又名线程驱动
),服务器资源耗费真的大。
1 | var fs = require("fs"); |