# Partilhe alguns threads de trabalho com NEWTHREADPOOL()

> Arranque um número fixo de workers, peça emprestado um com pool.exec() quando houver trabalho, devolva-o com release() e deixe os outros trabalhos esperar por um worker livre.

Framework: total5
Product: Total.js 5 (total5@0.0.19)
Language: pt
Content-SHA256: 8d9dad7033dd58d82d634887e767840094fa527f25d8bc54e3b6867db01088c7
Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c
Sources: total5-installed@total5@0.0.19
Review: not-recorded

`NEWTHREAD()` arranca um worker. Quando muitos pedidos precisam do mesmo trabalho pesado, um worker por pedido é demais e um único worker faz com que esperem uns pelos outros sem qualquer ordem. `NEWTHREADPOOL(name, count, [isfork])` arranca `count` workers de `workers/<name>.js` (um thread; com `isfork` em `true`, um processo filho, como `NEWFORK()`) e distribui-os um de cada vez.

- `pool.exec(function(worker, release) {})` espera até haver um worker livre e chama a sua função com ele. Envie-lhe o trabalho com `worker.postMessage(value)`, leia a resposta com `worker.once('message', fn)` e **chame `release()` quando terminar**: o worker volta ao pool e o próximo trabalho à espera fica com ele.
- Sem função, `pool.exec()` devolve uma promessa que se resolve com `worker` (e o worker tem `worker.release()`), pelo que funciona com `await`.
- Os trabalhos são atendidos pela ordem em que pediram. O pool não põe em fila as mensagens de um worker: um trabalho de cada vez tem-no.
- O pool também é guardado em `F.workers[name]`. `pool.workers` é a lista dos workers.

O ficheiro do worker é o mesmo que para `NEWTHREAD()`: `NEWTHREAD()` lá dentro devolve o manipulador com `worker.message` e `worker.postMessage()`. Aqui cada worker soma os números e diz que thread o fez.

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