Includes scratch-gui, scratch-vm, scratch-blocks, scratch-render, scratch-l10n, and deployment config. Co-authored-by: Cursor <cursoragent@cursor.com>
87 lines
2.3 KiB
JavaScript
87 lines
2.3 KiB
JavaScript
// 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();
|
||
}
|
||
} |