# Comparte unos pocos hilos de trabajo con NEWTHREADPOOL()

> Arranca un número fijo de workers, toma uno con pool.exec() cuando haya trabajo, devuélvelo con release() y deja que los demás trabajos esperen a un worker libre.

Framework: total5
Product: Total.js 5 (total5@0.0.19)
Language: es
Content-SHA256: 097f0216fba2494a8a1c28ad8d9cfda5ed7d29999e5c7a621b000b16d664fb28
Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c
Sources: total5-installed@total5@0.0.19
Review: not-recorded

`NEWTHREAD()` arranca un worker. Cuando muchas peticiones necesitan el mismo trabajo pesado, un worker por petición son demasiados y un único worker hace que se esperen unas a otras sin ningún orden. `NEWTHREADPOOL(name, count, [isfork])` arranca `count` workers de `workers/<name>.js` (un hilo; con `isfork` en `true`, un proceso hijo, como `NEWFORK()`) y los reparte de uno en uno.

- `pool.exec(function(worker, release) {})` espera hasta que hay un worker libre y llama a tu función con él. Envíale el trabajo con `worker.postMessage(value)`, lee la respuesta con `worker.once('message', fn)` y **llama a `release()` cuando termines**: el worker vuelve al pool y lo toma el siguiente trabajo que espera.
- Sin función, `pool.exec()` devuelve una promesa que se resuelve con `worker` (y el worker tiene `worker.release()`), de modo que funciona con `await`.
- Los trabajos se atienden en el orden en que lo pidieron. El pool no encola los mensajes de un worker: un trabajo a la vez lo tiene.
- El pool también se guarda en `F.workers[name]`. `pool.workers` es la lista de los workers.

El archivo del worker es el mismo que para `NEWTHREAD()`: `NEWTHREAD()` dentro de él devuelve el manejador con `worker.message` y `worker.postMessage()`. Aquí cada worker suma los números e indica qué hilo lo hizo.

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