ForgeTotal.js 5
en

Total.js 5

Share a few worker threads with NEWTHREADPOOL()

Total.js 5 · total5@0.0.19 workerthreadpoolperformance Executed against Total.js 5

NEWTHREAD() starts one worker. When many requests need the same heavy job, one worker per request is too many and a single worker makes them wait for each other without any order. NEWTHREADPOOL(name, count, [isfork]) starts count workers of workers/name.js (a thread; with isfork set to true a child process, like NEWFORK()) and hands them out one at a time.

  • pool.exec(function(worker, release) {}) waits until a worker is free and calls your function with it. Send it the work with worker.postMessage(value), read the answer with worker.once('message', fn) and call release() when you are done: the worker goes back to the pool and the next waiting job takes it.
  • Without a function, pool.exec() returns a promise that resolves with worker (and the worker has worker.release()), so it works with await.
  • The jobs are served in the order in which they asked. The pool does not queue the messages of a worker: one job at a time has it.
  • The pool is also kept in F.workers[name]. pool.workers is the list of the workers.

The worker file is the same as for NEWTHREAD(): NEWTHREAD() inside it returns the handle with worker.message and worker.postMessage(). Here every worker adds up the numbers and says which thread did it.

workers/total.js
require('total5');

const worker = NEWTHREAD();

worker.message = function(message) {
	let total = 0;
	for (let i = 1; i <= message.to; i++)
		total += i;
	worker.postMessage({ to: message.to, total: total, thread: require('worker_threads').threadId });
};
controllers/total.js
exports.install = function() {
	ROUTE('GET /total/{to}/', total);
	ROUTE('GET /await/{to}/', total_await);
	ROUTE('GET /workers/', workers);
};

const pool = NEWTHREADPOOL('total', 2);

function total($) {
	pool.exec(function(worker, release) {
		worker.once('message', function(response) {
			release();
			$.json(response);
		});
		worker.postMessage({ to: +$.params.to });
	});
}

async function total_await($) {
	const worker = await pool.exec();
	worker.once('message', function(response) {
		worker.release();
		$.json(response);
	});
	worker.postMessage({ to: +$.params.to });
}

function workers($) {
	$.json({ workers: pool.workers.length, registered: F.workers.total === pool });
}