Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: runConcurrently #75

Merged
merged 3 commits into from
Apr 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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();
});
Loading