跳至主要內容
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?

4563博客

全新的繁體中文 WordPress 網站
  • 首頁
  • 关于 worker_threads 执行顺序
未分類
15 11 月 2020

关于 worker_threads 执行顺序

关于 worker_threads 执行顺序

資深大佬 : hgjian 4

const { Worker, isMainThread, threadId , parentPort } = require(“worker_threads”);

function a(){
var worker = new Worker( __filename , { stdout : false , stderr : false } ) ;

worker.postMessage( { } )

worker.on( “message” , msg => {
console.log( ‘ 4 ‘ ) ;
console.log( ‘ 5 ‘ ) ;
console.log( ‘ 6 ‘ ) ;
} ) ;
}

function b(){

parentPort.on( “message” , msg => {

console.log( ‘ 1 ‘ ) ;
console.log( ‘ 2 ‘ ) ;
console.log( ‘ 3 ‘ ) ;

parentPort.postMessage( { } ) ;

} ) ;
}

if (isMainThread) {
a()
}else{
b()
}

请问打印结果为什么是
1
4
5
6
2
3
感觉应该是
1
2
3
4
5
6
才对啊。
win10,
nodr.js14
平台

大佬有話說 (20)

  • 資深大佬 : yyfearth

    我记得好像 console.log 有 buffer

  • 資深大佬 : mingl0280

    没人告诉过你线程的执行顺序看操作系统当时状态决定么?!谁告诉你线程执行序有保证的?!

  • 主 資深大佬 : hgjian

    @mingl0280 我是觉得,应该是

    顺序应该是 a 函数的 worker.postMessage( { } ) 触发 b 函数 执行 parentPort.postMessage( { } ) ;
    执行完 b 的 parentPort.postMessage( { } ) ; 才会触发 主线程的 worker.on 函数;

    请教一下,难道不是这样吗?

  • 主 資深大佬 : hgjian

    @yyfearth console.log 有 buffer,是什么意思啊?

  • 資深大佬 : yyfearth

    我记得 console.log 有 io 的 buffer
    所以可能 console.log 输出的时候比实际晚

    依旧是说 你 call parentPort.postMessage( { } ) 的时候 console 还在 buffer 里面
    然后不同的 worker buffer 不共享
    所以两者的输出穿插了

    当然这只是我的猜测

    你可以不用 console.log 用别的方法试试 比如直接输出 stdout 并且 flush

  • 資深大佬 : misdake

    我觉得可能的一种 145623 的运行顺序:(不保证正确)
    第一个 console.log(1)的时候,发起了刷 buffer 的请求,输出 1 。接下来的 bcde 因为没赶上这次的输出,被压进了主线程的 buffer,等待下一次刷新。
    worker 线程在跑的时候,1“正在”输出,刷新时 worker 线程的 buffer 里已经有 456 了,输出 456 。(猜测不同线程的刷新是轮询的,而不是优先盯着一个)
    下次刷主线程 buffer 的时候,buffer 里有 23,输出 23 。

    如果在 isMainThread 判断之前加上一句 console.log ,提前刷一下 console.log 的 buffer,输出的顺序应该就和你想象的一样了。感觉就是 buffer 相关的原因。

  • 主 資深大佬 : hgjian

    @yyfearth 感谢解答

  • 主 資深大佬 : hgjian

    @misdake 谢谢解答

  • 主 資深大佬 : hgjian

    @misdake
    如果在 isMainThread 判断之前加上一句 console.log ,提前刷一下 console.log 的 buffer,输出的顺序应该就和你想象的一样了。

    ===>> 在好几个地方 提前加了 console.log ,输出还是乱的,没有效果,我再研究看看有没有别的办法

  • 資深大佬 : des

    写是有 buffer 的,想要得到你预期的结果
    请使用 fs.writeFileSync(0, ‘stdout: ‘ + msg + ‘n’);

  • 資深大佬 : libook

    举个例子吧:
    你手里有 1 元、2 元、5 元的三张纸币,我手里有 10 元、20 元、100 元三张纸币,你走到一个存钱罐前,喊我过去和你一起把各自手里的纸币按照各自的从小到大顺序塞进存钱罐,但是存钱罐每次只能塞一张纸币,所以咱俩只要没有人堵着投币口就可以往里面塞,因为没有对双方塞入的顺序进行控制,所以一开始可能是我塞入第一张也可能是你塞入第一张,而且有可能是一个人塞得快连续塞入两张纸币第另个人才有机会塞入一张,也可能一个人在塞入某一张的时候卡住了需要更多时间调整姿态,另一个人得等着……总之,你就是没法确定你是第一个塞入 1 元的,我也没法确定我啥时候能塞入第一账;但是我们都能确定,你自己塞入的顺序一定是 1 元、2 元、5 元,我自己塞入的顺序一定是 10 元、20 元、100 元。

    引入多线程之后,就会有一个问题叫做“线程安全”,因为多个线程是同时运行的,所以在你没有特别控制执行顺序或确保最终一致性的措施的情况下,两个线程的执行顺序是不确定的,取决于你的操作系统和硬件当时是如何调度的。

    也就是说,只要你开辟了新的线程,就不要尝试去判断新线程里的程序啥时候执行。

    你可以判断同一线程内的执行顺序,比如 123 就是 123,不可能是 132,456 也一定是 456,不可能是 465 。

  • 資深大佬 : mingl0280

    @hgjian 线程 1 你 post 完 message 以后就是两个线程并行执行的……worker.on 又没说哪里来的 message (我估计这个 post 直接给两个函数都发送了信号)

  • 主 資深大佬 : hgjian

    @des 谢谢

  • 主 資深大佬 : hgjian

    @libook 谢谢你的详细说明

  • 主 資深大佬 : hgjian

    @mingl0280 谢谢说明

  • 資深大佬 : zy445566

    用[ncpu]( https://github.com/zy445566/ncpu)使用 await 可以保证顺序,但是如果要保证性能最大肯定也是 Promise.all 来 ncpu 的任务。也可以使用同一个 ncpuWorker 来保证执行顺序

  • 資深大佬 : zy445566

    上面链接多打了个空格导致 markdown 没识别,正确地址是: https://github.com/zy445566/ncpu

  • 資深大佬 : zy445566

    其实线程安全主要是集中在 CPU cache 的问题,因为 CPU cache 速度比内存要快,所以会从内存中复制一份数据到 CPU cache 中,运算完成之后再复制回内存。
    所以如果是单线程这样是没问题的,但是如果是多线程,就会出现一个时间差,比如两个线程先后复制到 CPU cache 中,但是计算完成后,再先后复制回内存。而这个时间差就会导致,一个线程计算的值不是另一个线程计算完成后的值,导致的线程不安全。
    但 JS 也有《 SharedArrayBuffer API 提供 Atomics 对象,保证所有共享内存的操作都是“原子性”的。》–这句话引用自阮一峰的 ECMAScript 6 入门

  • 主 資深大佬 : hgjian

    @zy445566 谢谢你的解释,我再看看你的 github 项目

  • 資深大佬 : no1xsyzy

    @mingl0280 worker.postMessage 给两个函数发信号的话 456 应该被打印两遍……
    这里其实相当于用 token 传递的方式进行了保序,那肯定是 console 带 buffer 的问题了。

文章導覽

上一篇文章
下一篇文章

AD

其他操作

  • 登入
  • 訂閱網站內容的資訊提供
  • 訂閱留言的資訊提供
  • WordPress.org 台灣繁體中文

51la

4563博客

全新的繁體中文 WordPress 網站
返回頂端
本站採用 WordPress 建置 | 佈景主題採用 GretaThemes 所設計的 Memory
4563博客
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?
在這裡新增小工具