Skip to content

Commit

Permalink
feat(engine): parallelize code execution (#80)
Browse files Browse the repository at this point in the history
## How does this PR impact the user?

This PR will speed up code execution in the engine by parallelizing it.

## Description

- [x] parallelize code execution

Below are the results on some synthetic test with 10 sequential vs 10
parallel runs.

### Before

<img width="475" alt="Screenshot 2024-11-17 at 11 44 26"
src="https://github.com/user-attachments/assets/4556f7eb-1c46-4691-8c90-4f1e897ccbbf">

### After: 5x win

<img width="458" alt="Screenshot 2024-11-17 at 11 43 36"
src="https://github.com/user-attachments/assets/e2e3cf13-0f73-424f-8ca5-80f27fca8130">

## Limitations

N/A

## Checklist

- [x] my PR is focused and contains one wholistic change
- [ ] I have added screenshots or screen recordings to show the changes
  • Loading branch information
yurijmikhalevich authored Nov 17, 2024
1 parent a429744 commit 600c4ee
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 19 deletions.
10 changes: 10 additions & 0 deletions other/CodeRunner.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,14 @@ describe("CodeRunner", () => {
// @ts-expect-error - we're testing a property that doesn't exist on the Array prototype
expect([].foo).toBeUndefined();
});

it("can run multiple scripts in parallel", async () => {
const scripts: string[] = [];
for (let i = 0; i < 10; i++) {
scripts.push(`for (let i = 0; i < 10_000_000; ++i) {}; 1 + ${i}`);
}
const codeRunner = new CodeRunner();
const results = await Promise.all(scripts.map(script => codeRunner.runCode(script)));
expect(results).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
});
});
38 changes: 19 additions & 19 deletions server/plugins/engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,7 @@ const GAME_STEP_INTERVAL_MS = 250;
const WORLD_SIZE = 600;

export const WORLD_REF = { world: new World ({ width: WORLD_SIZE, height: WORLD_SIZE }) };
const codeRunner = new CodeRunner();

async function runBot(code: string) {
const result = await codeRunner.runCode(code);
return JSON.parse(result);
}
const codeRunners = new Array(10).fill(0).map(() => new CodeRunner());

type RunBotArgs = {
bots: botCodeStore.BotCodes;
Expand All @@ -33,24 +28,29 @@ async function runBots({ bots, world, prevBotState, botApi }: RunBotArgs) {
const state = world.getState();
const botArray = Object.values(bots);

const botActions = [];
for (const bot of botArray) {
const preparedBotCodes = botArray.map(bot => prepareBotCode({
bot,
botInfo: bots,
state,
prevBotState,
botApi,
}));

const botActions = await Promise.all(preparedBotCodes.map(async (preparedCode, i) => {
const codeRunner = codeRunners[i % codeRunners.length];
if (!codeRunner) {
throw new Error("unexpected: codeRunner is undefined");
}

try {
const preparedCode = prepareBotCode({
bot,
botInfo: bots,
state,
prevBotState,
botApi,
});
const actions = await runBot(preparedCode);
botActions.push(actions);
const result = await codeRunner.runCode(preparedCode);
return JSON.parse(result);
} catch (err) {
// TODO(yurij): notify user that their bot crashed
console.error(err);
botActions.push([]);
return [];
}
};
}));

for (const [i, actions] of botActions.entries()) {
const botId = botArray[i]?.id;
Expand Down

0 comments on commit 600c4ee

Please sign in to comment.