一个普通的如果执行的时间太长会阻塞调度器。
rebar compile -> 编译
erl -pa ebin +P 120000 -> 进入shell.
执行cpu数量个进程,每个进程call到lua sleep 2s.
同步nif:所有的lua代码都执行在调度器上
直接阻塞调度器,block的时候无法输出tick.
elua_block:sync().
异步nif:所以的lua代码都在单独的线程池中执行,执行完了后返回结构。
调度器安全,一切正常。
elua_block:async().
- 本仓库已经实现了完整的异步线程池来在lua_state中执行代码。
- 已经经过比较充分的测试,目前看无bug,代码简单易读,容易移植。
- 每个发给lua_state的消息顺序保证不会乱,看了实现你就知道了。
- 异步nif只是比同步nif更安全,不会阻塞erlang的调度以发生莫名其妙的事情,其他并没有什么优势。
#下面的分析已经中毒了,各位不要看。
同步或者异步执行3w个lua进程。
可以在lua/block_400ms.lua中修改sleep的第1个参数作为处理ms.
-> finis 总时间 {Max,Min,Avg}
30000个同步2ms的调用, 期间会出现卡顿,CPU无法跑满2个核心以上
elua_block:r400ms_s(30000).
finis 26 {25976.904,658.49,13986.230306833386}
finis 26 {25945.968,7.806,13862.024351566612}
finis 28 {27250.5,2453.64,15311.128141300087}
finis 25 {24321.476,26.267,12693.977022566809}
30000个异步2ms的调用, 无卡顿,CPU可跑到250%.
elua_block:r400ms_a(30000).
finis 20 {19516.173,339.178,10995.266848766549}
finis 20 {19371.338,1321.542,10512.194497666595}
finis 21 {19837.564,585.391,11214.263717233302}
60000个同步2ms的调用, 期间会出现卡顿,CPU无法跑满2个核心以上
elua_block:r400ms_s(60000).
finis 77 {75254.873,4119.663,45753.99631433323}
finis 70 {69627.56,21.015,41680.500918383135} | 1400
60000个异步2ms的调用, 无卡顿,CPU利用率稍微好点,无法跑到200%
elua_block:r400ms_a(60000).
finis 69 {67116.629,97.854,40307.205141800354}
finis 76 {74833.706,16.887,46833.761039217155} |1300
finis 67 {66317.238,16.7,40975.44325593297} | 2000
finis 67 {65408.738,16.319,40731.685861699734}
4 worker 闲置唤醒下降到400,但是.
finis 179 {177993.277,10373.477,92834.48156833314}
16 worker
finis 167 {165790.4,17.289,81189.45815429992}
两个版本都大量的闲置唤醒。超过6W并发后,async版本也不管用,cpu无法跑到>200%
那么异步版本看上去也阻塞了调度器了,Why ?
elua_block:r400ms_pure_erlang(6000).
这行代码开启6k个erlang进程,在每个进程内跑个10ms左右的计算。在fork them all之后,cpu利用率可以达到97%,全部跑慢,不存在之前遇到的nif的跑不起cpu的情况。
cpu可以跑起来,但是明显的卡顿,用来测试单纯的无逻辑的nif消耗.
elua_block:nothing(4000).
elua_block:r400ms_a2(300).
cpu 轻松跑满,之前的sleep属于io,跑不起cpu是正常的。
elua_block:r400ms_s2(60000).
cpu 轻松跑满,之前的sleep属于io,跑不起cpu是正常的。
elua_block:r400ms_a2(60000).
所以:异步的nif和同步的nif其实只有不会阻塞调度器的区别,用起来会更安全。其他并没有什么好处。