Node.js 个工作线程共享 object/store

Node.js worker threads shared object/store

所以,我正在阅读一些关于 Node.js 的东西,当我遇到 Worker Threads.

时我感到很惊讶

在我看来,拥有线程是一个很好的优势,尤其是当您将它与共享内存访问结合使用时。正如您可能已经想到的那样 -> SharedArrayBuffer...

是的,我就是这么想的。所以我想到的第一件事就是给它做一个小测试,并尝试实现一个简单的 store(现在是一个简单的对象),它将在线程之间共享。

问题是,(除非我在这里遗漏了什么)如何使用 SharedArrayBuffer 使一个对象可以从 n 个线程访问?

我知道对于一个简单的Uint32Array是可以做到的,但是对于对象能做些什么呢?

起初我想把它转换成一个 Uint32Array ,你可能会在下面看到,但即使看着该死的源代码也让我想哭...

const {
    Worker,
    isMainThread,
    workerData
} = require('worker_threads');

const store = {
    ks109: {
        title: 'some title 1',
        description: 'some desciption 1',
        keywords: ['one', 'two']
    },
    ks110: {
        title: 'some title 2',
        description: 'some desciption 2',
        keywords: ['three', 'four']
    },
    ks111: {
        title: 'some title 3',
        description: 'some desciption 3',
        keywords: ['five', 'six']
    }
}

const shareObject = (obj) => {

    let OString = JSON.stringify(obj);
    let SABuffer = new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * OString.length);
    let sArray = new Int32Array(SABuffer);

    for (let i = 0; i < OString.length; i++) {
        sArray[i] = OString.charCodeAt(i);
    }

    return sArray;

}

if (isMainThread) {

    const sharedStore = shareObject(store);

    console.log('[Main][Data Before]:', sharedStore.slice(-10));

    let w = new Worker(__filename, {
        workerData: sharedStore
    });

    w.on('message', (msg) => {
        console.log(`[Main][Thread message]: ${msg}`);
    });
    w.on('error', (err) => {
        console.error(`[Main][Thread error] ${err.message}`);
    });
    w.on('exit', (code) => {
        if (code !== 0) {
            console.error(`[Main][Thread unexpected exit]: ${code}`);
        }
    });

    setInterval(() => {
        // At some point you ll see a value change,
        // it's 'six' becoming 'sax' (big time!) 
        console.log('[Main][Data Check]:', sharedStore.slice(-10));
    }, 1000);

} else {

    let str = String.fromCharCode.apply(this, workerData);
    let obj = JSON.parse(str);

    obj.ks111.keywords[1] = 'sax'; // big time!

    let OString = JSON.stringify(obj);

    for (let i = 0; i < OString.length; i++) {
        workerData[i] = OString.charCodeAt(i);
    }

}

综上所述,Node.js10.5.0中线程间共享对象,可能吗?怎么样?

ECMA 脚本不包含共享对象,但它有 SharedArrayBuffer。您可以使用 DataView 和 wrapper:

直接在缓冲区中直接写入数据来实现此类行为
// Shared value
class SharedPoint {
  constructor(array) {
    this.dataview = new DataView(array);
  }

  set x(value) {
    this.dataview.setUint8(0, value);
  }

  set y(value) {
    this.dataview.setUint8(1, value);
  }

  get x() {
    return this.dataview.getUint8(0);
  }

  get y() {
    return this.dataview.getUint8(1);
  }
}

// Usage

const buffer = new SharedArrayBuffer(2);

// Create two instances of shared point.
const point0 = new SharedPoint(buffer);
const point1 = new SharedPoint(buffer);

// Get initial values for point #1
console.log('x', point1.x); // 0
console.log('y', point1.y); // 0

// Update point #0
point0.x = 64;
point0.y = 32;

// Get changes in point #1
console.log('x', point1.x); // 64
console.log('y', point1.y); // 32

您可以创建 class 来操作字符串或 C 类结构 。虽然 SharedArrayBuffer 是可转移对象,但它可以在工作进程和主进程之间共享。

⚠️ Note Due to Spectre attack SharedArrayBuffer was disabled by all major browsers and reenabled. Though the API is mature, its' support could be lower than one might expect. Check browsers support at can i use.