Skip to content

Commit

Permalink
Improve pool documentation (#187)
Browse files Browse the repository at this point in the history
  • Loading branch information
andywer committed Dec 19, 2019
1 parent 5c7145e commit 4264ec9
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 4 deletions.
2 changes: 1 addition & 1 deletion docs/_data/navigation.yml
Expand Up @@ -15,7 +15,7 @@ sidebar:
url: /usage
- title: Observables
url: /usage-observables
- title: Thread pool
- title: Thread pools
url: /usage-pool
- title: Advanced
url: /usage-advanced
6 changes: 6 additions & 0 deletions docs/usage-advanced.md
Expand Up @@ -40,6 +40,12 @@ expose(function xorBuffer(buffer, value) {

Without `Transfer()` the buffers would be copied on every call and every return. Using `Transfer()` their ownership is transferred to the other thread instead only, to make sure it is accessible in a thread-safe way. This is a much faster operation.

## Task queue

It is a fairly common use case to have a lot of work that needs to be done by workers, but is just too much to be run efficiently at once. You will need to schedule tasks and have them dispatched and run on workers in a controlled fashion.

Threads.js does not provide a distinct task queue implementation, but it comes with [thread pools](./usage-pool.md) that covers the task queue functionality and more. Create a `Pool` and `.queue()` tasks to be dispatched to workers as they finish previous tasks.

## Thread events

Every spawned thread emits events during its lifetime that you can subscribe to. This can be useful for debugging.
Expand Down
50 changes: 47 additions & 3 deletions docs/usage-pool.md
Expand Up @@ -31,15 +31,59 @@ await pool.terminate()

Note that `pool.queue()` will schedule a task to be run in a deferred way. It might execute straight away or it might take a while until a new worker thread becomes available.

When a pool worker finishes a job, the next pool job is de-queued (that is the function you passed to `pool.queue()`). It is called with the worker as the first argument. The job function is supposed to return a promise - when this promise resolves, the job is considered done and the next job is de-queued and dispatched to the worker.
## Pool creation

```ts
interface PoolOptions {
concurrency?: number
name?: string
size?: number
}

function Pool(threadFactory: () => Thread, size?: number): Pool
function Pool(threadFactory: () => Thread, options?: PoolOptions): Pool
```

The first argument passed to the `Pool()` factory must be a function that spawns a worker thread of your choice. The pool will use this function to create its workers.

The second argument is optional and can either be the number of workers to spawn as a `number` or an options object (see `PoolOptions`):

- `options.concurrency`: number of tasks to run simultaneously per worker, defaults to one
- `options.name`: give the pool a custom name to use in the debug log, so you can tell multiple pools apart when debugging
- `options.size`: number of workers to spawn, defaults to the number of CPU cores

## Scheduling tasks

```ts
let pool: Pool<ThreadType>
type TaskFunction<ThreadType, T> = (thread: ThreadType) => Promise<T> | T
pool.queue<T>(task: TaskFunction<ThreadType, T>): Promise<T>
```

The promise returned by `pool.queue()` resolves or rejects when the queued task function has been run and resolved / rejected. That means *you should usually not `await` that promise straight away* when calling `pool.queue()`, since the code after this line will then not be run until the task has been run and completed.

Whenever a pool worker finishes a job, the next pool job is de-queued (that is the function you passed to `pool.queue()`). It is called with the worker as the first argument. The job function is supposed to return a promise - when this promise resolves, the job is considered done and the next job is de-queued and dispatched to the worker.

The promise returned by `pool.completed()` will resolve once the scheduled callbacks have been executed and completed. A failing job will also make the promise reject.

## Cancel a queued task
## Cancelling a queued task

You can cancel queued tasks, too. If the pool has already started to execute the task, you cannot cancel it anymore, though.

```js
const task = pool.queue(multiplier => multiplier(2, 3))
const task = pool.queue(multiplierWorker => multiplierWorker(2, 3))
task.cancel()
```

## Pool termination

```js
// Terminate gracefully
pool.terminate()

// Force-terminate pool workers
pool.terminate(true)
```

By default the pool will wait until all scheduled tasks have completed before terminating the workers. Pass `true` to force-terminate the pool immediately.

0 comments on commit 4264ec9

Please sign in to comment.