Skip to content

Commit

Permalink
feat: runConcurrently (#75)
Browse files Browse the repository at this point in the history
* init

* update

* update readme
  • Loading branch information
Aslemammad authored Apr 14, 2024
1 parent 764530b commit 4b8bd48
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 3 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ export type Hook = (task: Task, mode: "warmup" | "run") => void | Promise<void>;
```

- `async run()`: run the added tasks that were registered using the `add` method
- `async runConcurrently(limit: number = Infinity)`: similar to the `run` method but runs concurrently rather than sequentially
- `async warmup()`: warm up the benchmark tasks
- `reset()`: reset each task and remove its result
- `add(name: string, fn: Fn, opts?: FnOpts)`: add a benchmark task to the task map
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"publish": "npm run build && clean-publish",
"typecheck": "tsc --noEmit",
"release": "bumpp package.json --commit --push --tag && npm run publish",
"test": "vitest --retry=3 --run"
"test": "vitest --retry=5 --run"
},
"main": "./dist/index.cjs",
"module": "./dist/index.js",
Expand Down
41 changes: 39 additions & 2 deletions src/bench.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ export default class Bench extends EventTarget {
}
}

runTask(task: Task) {
if (this.signal?.aborted) return task;
return task.run();
}

/**
* run the added tasks that were registered using the
* {@link add} method.
Expand All @@ -76,13 +81,45 @@ export default class Bench extends EventTarget {
this.dispatchEvent(createBenchEvent('start'));
const values: Task[] = [];
for (const task of [...this._tasks.values()]) {
if (this.signal?.aborted) values.push(task);
else values.push(await task.run());
values.push(await this.runTask(task));
}
this.dispatchEvent(createBenchEvent('complete'));
return values;
}

/**
* similar to the {@link run} method but runs concurrently rather than sequentially
* default limit is Infinity
*/
async runConcurrently(limit = Infinity) {
this.dispatchEvent(createBenchEvent('start'));

const remainingTasks = [...this._tasks.values()];
const values: Task[] = [];

const handleConcurrency = async () => {
while (remainingTasks.length > 0) {
const runningTasks: (Promise<Task> | Task)[] = [];

// Start tasks up to the concurrency limit
while (runningTasks.length < limit && remainingTasks.length > 0) {
const task = remainingTasks.pop()!;
runningTasks.push(this.runTask(task));
}

// Wait for all running tasks to complete
const completedTasks = await Promise.all(runningTasks);
values.push(...completedTasks);
}
};

await handleConcurrency();

this.dispatchEvent(createBenchEvent('complete'));

return values;
}

/**
* warmup the benchmark tasks.
* This is not run by default by the {@link run} method.
Expand Down
34 changes: 34 additions & 0 deletions test/sequential.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,37 @@ test('sequential', async () => {
await sequentialBench.run();
expect(isFirstTaskDefined).toBe(true);
});

test('concurrent', async () => {
const concurrentBench = new Bench({
time: 0,
iterations: 100,
});

let shouldBeDefined1: true;
let shouldBeDefined2: true;

let shouldNotBeDefinedFirst1: true;
let shouldNotBeDefinedFirst2: true;
concurrentBench
.add('sample 1', async () => {
shouldBeDefined1 = true;
await setTimeout(100);
shouldNotBeDefinedFirst1 = true;
})
.add('sample 2', async () => {
shouldBeDefined2 = true;
await setTimeout(100);
shouldNotBeDefinedFirst2 = true;
});

concurrentBench.runConcurrently();
await setTimeout(0);
expect(shouldBeDefined1!).toBeDefined();
expect(shouldBeDefined2!).toBeDefined();
expect(shouldNotBeDefinedFirst1!).toBeUndefined();
expect(shouldNotBeDefinedFirst2!).toBeUndefined();
await setTimeout(100);
expect(shouldNotBeDefinedFirst1!).toBeDefined();
expect(shouldNotBeDefinedFirst2!).toBeDefined();
});

0 comments on commit 4b8bd48

Please sign in to comment.