Last active
August 19, 2019 13:00
-
-
Save broofa/d68614e44e68d4e08937cbaeaad5a3a1 to your computer and use it in GitHub Desktop.
Playing around with worker_threads
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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