当前位置: 首页 > 后端技术 > Node.js

JSRE中的多任务和多线程

时间:2023-04-03 17:30:18 Node.js

前言这几天在爱智官网上看了JSRE的其他API,看到了一个比较有意思的模块——多任务模块task。案例,感觉跟多线程差不多,接下来我要看实现方法了。找了半天也没找到源码(╬ ̄盘 ̄)。问了他们的工作人员才知道源码还没有放出来,我只能等,等等……凌晨3点30分起床,继续敲代码。信誉取决于人品!!!没有源码的加持,我只能轻装上阵。感觉这装备经不起你们第一轮的写啊……希望在座的各位都能做个人,啊不,做个猿(元)!多任务简介经过一番努力,终于为大家带来了第一手资料。据可靠消息(PS:其实我只是直接从他们官网复制了一点官方介绍(???)?):JSRE中创建的每一个Task在操作系统中都是一个独立的线程,操作系统可以根据调度策略独立调度,用于提高应用程序的并行性。Node.js等运行时平台虽然通过多线程异步代理实现了并行化,但是核心程序流程无法并行化,程序员的可控性太低(这一点我很认同),没有可控的策略。此外,多任务模块还提供了更好的应用代码解耦。应用模块的分离和开发,更容易构建更复杂的大型应用。上面一大段内容,我打出来用了3秒,感觉自己从三岁开始敲键盘的功夫岁月没有白过!(?﹏?).我们都知道Node.js是单线程的,但这仅仅意味着js执行的主线程是单线程的。其他异步IO和事件驱动相关线程通过libuv实现内部线程池和线程调度,只负责连续往返。调度不进行真正的I/O操作,从而实现异步非阻塞I/O。[提问]:据说JSRE中的每个任务都是一个独立的线程。JSRE本身是否支持多线程?【答案】:别想了,我不是很了解,在官网也没有找到准确的答案,还是继续修行,长见识吧!示例测试1.同步执行测试代码://main.js...console.info('start');//模拟3s耗时操作lett=0;while(t<3000){console.warn('等待...');系统睡眠(1000);t+=1000;}console.info('end');...运行结果:我们在入口文件main.js中加入上面的测试代码,我们都知道js代码是从上到下顺序执行的,我们在主线程中添加了一个3秒的阻塞代码。当然,在实际项目中,启动一个服务可能需要更多的时间。从VSCode的输出窗口中,我们可以看到日志是按顺序打印的。打印结束前等待3秒后,主程序阻塞3秒。这时候用户体验会很卡。阻塞的3秒对后面主线程的代码执行没有影响。在实际项目中,可能会启用一些应用的其他附加服务。接下来,我将使用多任务模块来处理阻塞代码。2.多任务执行测试代码://main.js...console.info('start');//启动子任务newTask('./task.js');console.info('end');...//task.jslett=0;while(t<3000){console.warn('wait...');系统睡眠(1000);t+=1000;}运行结果:上面的测试代码代码中,我们将3秒阻塞代码放在新建的task.js文件中。在main.js中,我们通过Task模块实例化了一个多任务实例,参数为task.js的文件地址。此时运行代码,我们可以看到end字段的打印并没有受到多任务实例中阻塞代码的影响,从而不会对主线程造成不必要的阻塞。在Node.js中,异步I/O可以交给内部线程池、工作线程或子进程处理。对于数据通信,我们都知道线程是并行运行的,一个线程不能直接访问其他线程的内部数据。按照官网的说法,每个多任务是一个线程,多任务之间的数据要单独维护。孤立。那么多个任务之间如何进行数据通信呢?这里,在爱知开发手册中,我们可以看到,多个任务之间的通信方式有很多种。其中一个比较有特色的是一个名为SyncTable的共享映射数据库。个人感觉这个模块的具体功能应该是js模块之间的通信(纯属个人观点,写错勿喷!)。废话不多说,言归正传!这里就来看看其中一种多任务通信方式:信号槽通信(SigSlot)。官网介绍:SigSlot是一个事件驱动的异步通信组件,支持多任务多处理。如果需要多进程支持,则必须启动JSRE(全局信号槽)并在启动进程时使用-g选项启用当前进程GSS支持。在EdgerOS中,来自同一供应商的应用程序可以使用GSS功能相互订阅和发布消息。SigSlot是一种典型的订阅和发布通信机制。基于SigSlot,可以轻松进行多任务解耦。每个任务都是独立设计的,大大降低了应用开发的难度。让我们直接使用这个模块:测试代码//main.js...constSigSlot=require('sigslot');consttestSlot=newSigSlot('test');testSlot.slot('task',(msg)=>{console.log('main:',msg);testSlot.emit('main','maintotask');})newTask('./task.js');...//task.jsconstSigSlot=require('sigslot');consttestSlot=newSigSlot('test');testSlot.slot('main',(msg)=>{console.log('task:',msg);})testSlot.emit('task','tasktomain');require('iosched').forever();运行结果:从运行结果可以看出,在JSRE中,可以通过信号槽在多个任务之间传输数据相互传递是指多任务之间可以进行数据通信,主要依靠发布-订阅模型来实现模块间通信的功能。其实一开始的结果是只打印了main.js订阅的task事件,而没有在task.js中打印mian.js中发布的主要事件。我很困惑,并根据官方网站的用法检查了几次。如果发现书写有误,直接排除书写问题。定位到应该是事件处理程序的位置不会被触发。这时,我注意到了iosched模块。经过一番查找,我终于知道了原因。该模块是JSRE的核心模块之一,简单理解为处理异步I/0事件调度。如果想让js模块一直执行异步事件循环,可以显式调用模块的forever方法来实现(require('iosched').forever())。这与Node.js非常不同。为什么JSRE这样做?处理?遗憾的是,这不是今天的重点,稍后再介绍这个模块。多任务总结JSRE中的多任务模块,我感觉非常好。首先,这种多任务的写法比较直观,个人比较推荐;其次,多任务处理是可控的。JSRE也为这个模块提供了很多功能。其他接口供开发人员执行任务控制。上图是个人使用最直观的感受。至于底层多任务的实现,以及JSRE本身是不是多线程机制,可能要等开源了才知道。这次到此为止就够了。上面JSRE的异步事件循环机制和Node.js内置事件循环的异同,下回会通过对比来说明。以上如有不妥,欢迎在下方评论。