# Share a few worker threads with NEWTHREADPOOL()

> Start a fixed number of workers, borrow one with pool.exec() when there is work, give it back with release(), and let the other jobs wait for a free worker.

Framework: total5
Product: Total.js 5 (total5@0.0.19)
Language: en
Content-SHA256: 6fbb579ec2a9b0a43ee3b6a86ea83738bde754d17a73392805d15250c0db98d6
Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c
Sources: total5-installed@total5@0.0.19
Review: not-recorded

`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.

```js 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 });
};
```

```js 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 });
}
```
