Skip to content

Commit

Permalink
Wrote readme and added exceptions
Browse files Browse the repository at this point in the history
  • Loading branch information
eliassjogreen committed Apr 18, 2020
1 parent ed2d5ca commit a651439
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 7 deletions.
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2019 Elias
Copyright (c) 2019-2020 Elias

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
54 changes: 53 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,54 @@
# parry
A simple way of running functions in their own WebWorker. Mainly for deno

A simple way of running functions in their own WebWorker that works with
[deno](https://deno.land/).

## Usage

The following function will run in it's own WebWorker, enabling threading and
therefor not blocking the main event loop. This becomes very useful for
parallelization of certain computations or just a way of running a function and
not blocking the main event loop while it runs.

```ts
import { parry } from "https://deno.land/x/parry/mod.ts";

async function countSerial(limit: number): Promise<void> {
for (let i = 0; i < limit; i++) {}
}

console.time("4x CountSerial");
await Promise.all([
countSerial(1e9),
countSerial(1e9),
countSerial(1e9),
countSerial(1e9),
]);
console.timeEnd("4x CountSerial");

const threads = [
parry(countSerial),
parry(countSerial),
parry(countSerial),
parry(countSerial),
];

console.time("4x CountParallel");
await Promise.all([
threads[0](1e9),
threads[1](1e9),
threads[2](1e9),
threads[3](1e9),
]);
console.timeEnd("4x CountParallel");

parry.close();
```

The parallelized version is 4x faster than the serial version of the count
function:

```
4x CountSerial: 1885ms
4x CountParallel: 509ms
```
48 changes: 43 additions & 5 deletions mod.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@
class ParryError extends Error {
constructor(message: string = "") {
super(message);
this.name = this.constructor.name;
this.stack;
}
}

type AsyncFunction<S extends any[], T> = (...args: S) => Promise<T>;
type MaybeAsyncFunction<S extends any[], T> = (...args: S) => T | Promise<T>;

interface ParryFunction<S extends any[], T> extends AsyncFunction<S, T> {
id: number;
closed: boolean;
close: () => void;
set: (f: MaybeAsyncFunction<S, T>) => void;
}

const funcs: Map<number, ParryFunction<any, any>> = new Map();
let funcsIndex: number = 0;

export function parry<S extends any[], T>(
original: (...args: S) => T | Promise<T>,
): ParryFunction<S, T> {
Expand Down Expand Up @@ -36,7 +49,11 @@ export function parry<S extends any[], T>(
delete promises[id];
};

const call: ParryFunction<S, T> = (...args: S[]): Promise<T> => {
const func: ParryFunction<S, T> = (...args: S[]): Promise<T> => {
if (func.closed) {
throw new ParryError("Cannot run closed WebWorker");
}

return new Promise((resolve, reject) => {
promises[id] = [resolve, reject];
worker.postMessage({
Expand All @@ -49,20 +66,41 @@ export function parry<S extends any[], T>(
});
};

call.close = (): void => {
func.id = funcsIndex++;
func.closed = false;

func.close = (): void => {
if (func.closed) {
throw new ParryError("Cannot close already closed WebWorker");
}

worker.postMessage({ type: "close" });
func.closed = true;
funcs.delete(func.id);
};

call.set = (f: MaybeAsyncFunction<S, T>): void => {
func.set = (f: MaybeAsyncFunction<S, T>): void => {
if (func.closed) {
throw new ParryError("Cannot set closed WebWorker");
}

worker.postMessage({
type: "set",
data: f.toString(),
});
};

call.set(original);
func.set(original);

funcs.set(func.id, func);

return call;
return func;
}

parry.close = (): void => {
for (const [id, func] of funcs) {
func.close();
}
};

export default parry;

0 comments on commit a651439

Please sign in to comment.