// PyodideWorkerPool.js export default class PyodideWorkerPool { constructor(poolSize = 2) { this.poolSize = poolSize; this.workers = []; this.onMessageCallbacks = []; this.initPool(); } initPool() { for (let i = 0; i < this.poolSize; i++) { this.workers.push(this.createWorker()); } } createWorker() { const workerInfo = { worker: new Worker('js/pyodideWorker.js'), busy: false, loaded: false }; // 监听 Worker 消息 workerInfo.worker.onmessage = (event) => { const { type } = event.data; if (type === "finish") { workerInfo.loaded = true; } if (type === "executionComplete" || type === "error") { workerInfo.busy = false; } // 让外部知道“是哪个 worker 发来的消息” for (let cb of this.onMessageCallbacks) { cb(event, workerInfo); } this.updateIsPythonLoadOK(); }; return workerInfo; } addOnMessageListener(callback) { this.onMessageCallbacks.push(callback); } updateIsPythonLoadOK() { // 只要至少一个 Worker loaded 就算可以执行 const anyLoaded = this.workers.some(w => w.loaded === true); window.isPythonLoadOK = anyLoaded; } // 找到不忙、且已loaded的 Worker getFreeWorker() { return this.workers.find(w => w.busy === false && w.loaded === true) || null; } // 让指定 Worker 执行 runPython(workerInfo, code) { if (workerInfo.busy) { throw new Error("该 Worker 正在执行脚本,无法重复使用"); } if (!workerInfo.loaded) { throw new Error("该 Worker 尚未加载 Pyodide,无法执行 Python"); } workerInfo.busy = true; workerInfo.worker.postMessage({ type: "runPython", code }); } // 停止并替换 terminateAndReplace(workerInfo) { workerInfo.worker.terminate(); const idx = this.workers.indexOf(workerInfo); if (idx !== -1) { const newW = this.createWorker(); this.workers[idx] = newW; } this.updateIsPythonLoadOK(); } destroyPool() { for (let wInfo of this.workers) { wInfo.worker.terminate(); } this.workers = []; this.updateIsPythonLoadOK(); } }