如何更爽的在 JS 中使用多线程 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
zy445566
V2EX    Node.js

如何更爽的在 JS 中使用多线程

  •  1
     
  •   zy445566 2020-09-08 09:33:05 +08:00 6557 次点击
    这是一个创建于 1885 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近写多线程的时候遇到一个烦恼,就是用起来实在太麻烦,不管是 WebWorker 还是 worker_threads 库,用起来都实在太麻烦了。而且很多时候 IO 密集和 CPU 密集操作很多时候是交织的,有没有一种办法,可以直接在代码中方便的使用多线程呢?

    以前我们使用 Worker 要怎么做?现在我们能怎么做?

    之前的做法:

    // ### 父进程代码 // 比如请求网络数据,IO 操作 const apiData = await request('/api/xxx'); // 为了不阻塞 eventloop 开启子线程,并拿到符合要求的格式 const goodApiData = await new Promise((resolve, reject) => { const worker = new Worker('子进程文件名 xxx.js', { workerData: apiData }); worker.on('message', resolve); worker.on('error', reject); }); // ### 子线程代码 // 这里处理 data 数据,CPU 密集操作 doSomething(workerData) // 再发送回父进程 parentPort.postMessage(data); 

    代码量这么大,还要写 2 个文件以上文件,数据发送过去再发送回来头都大了!!!费脑!!!

    那有没有更好的方法呢?当然使用 ncpu 就能做到!

    使用 ncpu 的做法:

    import {NCPU} from 'ncpu' // 比如请求网络数据,IO 操作 const apiData = await request('/api/xxx'); // 为了不阻塞 eventloop 开启子线程,并拿到符合要求的格式 const goodApiData = await NCPU.run((data)=>{ // 这里处理 data 数据,CPU 密集操作 doSomething(data) return data; }, [apiData]) //使用数组传参,这有点类似 apply 

    使用 ncpu 果然爽,一个回调函数就把 CPU 密集型计算搞定了。

    爽是爽,但目前有两点强制限制:

    • 回调函数不能共用上下文,因为 ncpu 是使用函数复制的方式来实现的,不会保留函数上下文,所以要求函数是强无副作用函数。
    • 传入参数都是使用 HTML structured clone algorithm方式来进行克隆的,而非原值。

    但正是这两点强制限制,使得线程更加安全了。因为但多个线程同时操作原值,会导致内存数据更新速度赶不上线程更新的速到,导致另一个线程读取数据不正确。而且我们要处理数据时,通常只需要将大循环和递归计算放入线程的回调函数中,所以这两点强制,反而不是坏事。

    目前 ncpu 的两个版本

    一个是ncpu专门为 node.js 环境设计,另一个是ncpu-web专门为浏览器环境设计。

    同时ncpu需要的最低 node.js 版本是 12,而ncpu-web浏览器要求是谷歌浏览器至少 60 以上,火狐 57 以上即可。

    在使用的时候要注意这些问题哦!

    18 条回复    2020-09-08 17:01:32 +08:00
    way2explore2
        1
    way2explore2  
       2020-09-08 09:35:59 +08:00
    我最近写了一个多进程的工具。pambdajs


    https://github.com/tim-hub/pambdajs
    zy445566
        2
    zy445566  
    OP
       2020-09-08 09:43:01 +08:00   1
    @way2explore2 天呐!我们想到一块去了!棒!你文档比我写的好,但我多了个前端版本,哈哈
    oubenruing
        3
    oubenruing  
       2020-09-08 09:58:11 +08:00   1
    微软有个 js 的多线程运行时。
    https://github.com/microsoft/napajs
    zy445566
        4
    zy445566  
    OP
       2020-09-08 10:04:03 +08:00
    @oubenruing 我知道这个,但这个缺点也明显有 C++库依赖,而且已经很多年没维护了,高版本 node 都没法使用了
    EPr2hh6LADQWqRVH
        5
    EPr2hh6LADQWqRVH  
       2020-09-08 10:19:59 +08:00 via Android
    js 的 cpu 密集型。。能密集到哪去。。。
    hhgfy
        6
    hhgfy  
       2020-09-08 10:29:15 +08:00   1
    不用单独拆文件倒是挺不错的
    zy445566
        7
    zy445566  
    OP
       2020-09-08 10:41:27 +08:00
    @avastms
    前端可能就是渲染和画图会用到,大部分不需要,node.js 服务端多些。其实目的就只有一个防止阻塞 eventloop 。
    之前 node.js 服务端都是用尽可能分片拆代码来实现拆解 CPU 密集运算,从而防止阻塞 eventloop,现在多了一种更方便的选择。
    LennieChoi
        8
    LennieChoi  
       2020-09-08 11:23:24 +08:00
    node12 有原生的多线程啊,好用
    zy445566
        9
    zy445566  
    OP
       2020-09-08 11:45:40 +08:00
    @LennieChoi 我就是基于原生多线程写的,就是觉得原生多线程麻烦要互相通讯
    whincwu142
        10
    whincwu142  
       2020-09-08 12:06:15 +08:00 via Android   1
    @way2explore2 好奇怎么做到的,看了下源码才知道,学习了。

    我理解的思路:将要在线程中执行的纯函数和参数序列化成字符串,通过环境产量传递给 fork 出的进程,进程中加载预定的 js 模板,解析环境变量中传入的纯函数和参数,拼接成函数通过 eval 执行,并返回结果给主进程,主进程聚合子进程结果后返回。最终实现了在主进程批量调用函数并返回结果,这些函数在子进程中执行。

    如有不对,还请指教
    OHyn
        11
    OHyn  
       2020-09-08 12:36:59 +08:00 via Android   1
    哇!!!
    前几天写个 webworker 搞得头痛,传来传去好麻烦。加上 webpack 打包更是好多坑,最加上 worker-lplugin 才勉强用起来。
    zy445566
        12
    zy445566  
    OP
       2020-09-08 12:47:17 +08:00
    @OHyn 对的,我最后是用了 BlobURL 实现在 webpack 打包的
    way2explore2
        13
    way2explore2  
       2020-09-08 14:41:18 +08:00
    @whincwu142 你说得完全正确。

    还没来得及仔细读你的代码?还不知道你的具体实现方式是?
    way2explore2
        14
    way2explore2  
       2020-09-08 14:44:11 +08:00
    @whincwu142 不好意思回复错了,还以为你是题主。后边的问题是问题主的 @zy445566
    way2explore2
        15
    way2explore2  
       2020-09-08 14:45:46 +08:00
    @zy445566 是啊,child_process 不在 browser 工作
    way2explore2
        16
    way2explore2  
       2020-09-08 15:22:04 +08:00
    要做一个 readme 友情链接吗?

    我把 ncpu 添加到 readme 里了 作为相关项目。

    https://github.com/tim-hub/pambdajs
    zy445566
        17
    zy445566  
    OP
       2020-09-08 16:57:28 +08:00
    @way2explore2
    其实我的实现方式有点类似。已添加友情链。


    https://github.com/zy445566/ncpu


    https://github.com/zy445566/ncpu-web
    flowfire
        18
    flowfire  
       2020-09-08 17:01:32 +08:00 via Android
    只用多线程不用 wasm 感觉没多大意义………
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5400 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 28ms UTC 01:29 PVG 09:29 LAX 17:29 JFK 20:29
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86