Initial commit of 001code-html Scratch frontend project.
Includes scratch-gui, scratch-vm, scratch-blocks, scratch-render, scratch-l10n, and deployment config. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
87
scratch-gui/static/js/PyodideWorkerPool.js
Normal file
87
scratch-gui/static/js/PyodideWorkerPool.js
Normal file
@@ -0,0 +1,87 @@
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user