Skip to content

Instantly share code, notes, and snippets.

@broofa
Last active August 19, 2019 13:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save broofa/d68614e44e68d4e08937cbaeaad5a3a1 to your computer and use it in GitHub Desktop.
Save broofa/d68614e44e68d4e08937cbaeaad5a3a1 to your computer and use it in GitHub Desktop.
Playing around with worker_threads
const {Worker, isMainThread, parentPort, workerData} = require('worker_threads');
const gameIdToWorker = new Map();
const gameIds = []; // Not required. just makes it easy to pick a random game id
let messageCount = 0;
/** Initialize a worker thread */
function makeWorker(workerId) {
const worker = new Worker(__filename, {workerData: {workerId}});
// Handle messages from worker
worker.on('message', msg => {
messageCount++;
if (messageCount % 10000 == 0) {
console.log(`Game action #${messageCount}`, msg);
}
});
// Lifecycle events
worker.on('error', err => console.error('Error', workerId, err));
worker.on('exit', code => console.log('EXIT', workerId, code));
// Create some games for the worker to manage
for (let i = 0; i < 3; i++) {
// Pick an id for the gamej
const gameId = workerId * 100 + 1;
// Tell worker to create the game
worker.postMessage({action: 'create', gameId});
// Keep track of which workers have which games
gameIdToWorker.set(gameId, worker);
gameIds.push(gameId); // So we can easily pick games at random
}
}
/** Simulate game actions, self-invokes as rapidly as possible*/
function doSomeGameAction() {
const gameId = gameIds[Math.floor(Math.random() * gameIds.length)];
const worker = gameIdToWorker.get(gameId);
if (!worker) throw Error(`Invalid worker ${gameId}`);
worker.postMessage({action: 'poke', gameId});
// ... and repeat ASAP
setImmediate(doSomeGameAction);
}
if (isMainThread) {
// Create some workers
const numCPUs = require('os').cpus().length;
for (let i = 0; i < numCPUs; i++) makeWorker(i);
// Start simulating game actions
doSomeGameAction();
} else {
const config = workerData;
// Minimal game class with state and an action method
class Game {
count = 0;
poke() {
this.count++
}
}
// Games this worker is responsible for
const games = new Map();
// Handle messages from parent
parentPort.on('message', msg => {
switch (msg.action) {
case 'config':
break;
case 'create':
games.set(msg.gameId, new Game());
break;
case 'poke':
const game = games.get(msg.gameId);
// Update game state
game.poke();
// Pass state back to main thread
parentPort.postMessage({gameId: msg.gameId, count: game.count});
break;
}
});
console.log(`Worker ${config.workerId} ready`);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment