簡體   English   中英

在node.js中,如何聲明一個可以被master進程初始化並被worker進程訪問的共享變量?

[英]In node.js, how to declare a shared variable that can be initialized by master process and accessed by worker processes?

我想要以下

  • 在啟動期間,主進程從文件中加載一個大表並將其保存到一個共享變量中。 該表有 9 列和 1200 萬行,大小為 432MB。
  • 工作進程運行 HTTP 服務器,接受對大表的實時查詢。

這是我的代碼,顯然沒有達到我的目標。

var my_shared_var;
var cluster = require('cluster');
var numCPUs = require('os').cpus().length;

if (cluster.isMaster) {
  // Load a large table from file and save it into my_shared_var,
  // hoping the worker processes can access to this shared variable,
  // so that the worker processes do not need to reload the table from file.
  // The loading typically takes 15 seconds.
  my_shared_var = load('path_to_my_large_table');

  // Fork worker processes
  for (var i = 0; i < numCPUs; i++) {
    cluster.fork();
  }
} else {
  // The following line of code actually outputs "undefined".
  // It seems each process has its own copy of my_shared_var.
  console.log(my_shared_var);

  // Then perform query against my_shared_var.
  // The query should be performed by worker processes,
  // otherwise the master process will become bottleneck
  var result = query(my_shared_var);
}

我嘗試將大表保存到 MongoDB 中,以便每個進程都可以輕松訪問數據。 但是表太大了,即使有索引,MongoDB 也需要大約 10 秒才能完成我的查詢。 這太慢了,對於我的實時應用程序來說是不可接受的。 我也嘗試過 Redis,它將數據保存在內存中。 但是 Redis 是一個鍵值存儲,我的數據是一個表。 我還寫了一個 C++ 程序將數據加載到內存中,查詢時間不到 1 秒,所以我想在 node.js 中進行模擬。

如果我用幾句話翻譯您的問題,您需要與WORKER實體共享MASTER實體的數據。 使用事件可以非常輕松地完成:

從師父到工人:

worker.send({json data});    // In Master part

process.on('message', yourCallbackFunc(jsonData));    // In Worker part

從工人到大師:

process.send({json data});   // In Worker part

worker.on('message', yourCallbackFunc(jsonData));    // In Master part

我希望通過這種方式可以雙向發送和接收數據。 如果您發現它有用,請將其標記為答案,以便其他用戶也可以找到答案。 謝謝

您正在尋找共享內存, node.js不支持 您應該尋找替代方案,例如查詢數據庫或使用memcached

如果只讀訪問適用於您的應用程序,請嘗試使用我自己的共享內存模塊 它使用了mmap ,因此數據在訪問時加載,而不是一次性加載。 內存在機器上的所有進程之間共享。 使用它非常簡單:

const Shared = require('mmap-object')

const shared_object = new Shared.Open('table_file')

console.log(shared_object.property)

它為您提供了一個到字符串或數字的鍵值存儲的常規對象接口。 它在我的應用程序中超級快。

還有一個可用於測試的模塊實驗性讀寫版本

在node.js中,fork的工作方式與C ++不同。 它不是復制當前的進程狀態,而是運行新進程。 因此,在這種情況下,不共享變量。 每行代碼都適用於每個進程,但主進程將cluster.isMaster標志設置為true。 您需要為每個工作進程加載數據。 如果您的數據非常龐大,請小心,因為每個進程都有自己的副本。 我認為您需要在需要時立即查詢部分數據,或者如果您真的需要在內存中使用它,請等待。

你可以使用Redis。

Redis是一個開源的,BSD許可的,高級鍵值緩存和存儲。 它通常被稱為數據結構服務器,因為密鑰可以包含字符串,散列,列表,集,排序集,位圖和超級日志。

redis.io

這種方式可以“共享變量”; 它比@Shivam 呈現的方式更花哨。 但是,該模塊在內部使用相同的 API。 因此“共享內存”有點誤導,因為在集群中每個進程都是父進程的一個分支。 在 fork 時,進程內存在 OS 內存中復制。 因此,除了像 shm 設備或虛擬共享內存頁面(Windows)這樣的低級共享內存之外,沒有真正的共享內存。 我確實為 Node.js 實現了一個本機模塊,它使用本機共享內存(這是真正的共享內存),因為使用這種技術,兩個進程都直接從操作系統共享內存部分讀取。 但是,此解決方案在這里並不適用,因為它僅限於標量值。 您當然可以 JSON.stringify 並共享 JSON 序列化數據字符串,但解析/字符串化所消耗的時間對於大多數用例來說完全不理想。 (特別是對於較大的對象,使用標准庫實現對 JSON 的解析/字符串化變得非線性)。

因此,這個解決方案目前似乎是最有前途的:

const cluster = require('cluster');
require('cluster-shared-memory');

if (cluster.isMaster) {
  for (let i = 0; i < 2; i++) {
    cluster.fork();
  }
} else {
  const sharedMemoryController = require('cluster-shared-memory');
  // Note: it must be a serializable object
  const obj = {
    name: 'Tom',
    age: 10,
  };
  // Set an object
  await sharedMemoryController.set('myObj', obj);
  // Get an object
  const myObj = await sharedMemoryController.get('myObj');
  // Mutually exclusive access
  await sharedMemoryController.mutex('myObj', async () => {
    const newObj = await sharedMemoryController.get('myObj');
    newObj.age = newObj.age + 1;
    await sharedMemoryController.set('myObj', newObj);
  });
}

這個問題是在 2012 年發布的,正好是 10 年前。 由於沒有其他答案提到它,Node.js 現在支持支持共享內存的工作線程<\/a>。

直接來自文檔:

工作者(線程)對於執行 CPU 密集型 JavaScript 操作很有用。 與 child_process 或 cluster 不同,worker_threads 可以共享內存。 他們通過傳輸 ArrayBuffer 實例或共享 SharedArrayBuffer 實例來做到這一點。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM