Commit 7d3e87ac authored by Boxiang Sun's avatar Boxiang Sun

Webworker experiment

parent 45e2630e
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
cell_type_regexp = /^\%\% (\w+)\b/, cell_type_regexp = /^\%\% (\w+)\b/,
language_type_regexp = /\{[\S\s]+\}/, language_type_regexp = /\{[\S\s]+\}/,
is_pyodide_loaded = false, is_pyodide_loaded = false,
is_matplotlib_used = true,
Module = {}, Module = {},
packages, packages,
loadedPackages = [], loadedPackages = [],
...@@ -41,17 +42,46 @@ ...@@ -41,17 +42,46 @@
py_div_id_count = 0, py_div_id_count = 0,
py_div_id_count_2 = 0, py_div_id_count_2 = 0,
props = {}, props = {},
worker = new Worker('worker_load_pyodide.js'),
// Regexp for validating package name and URI // Regexp for validating package name and URI
package_name_regexp = '[a-z0-9_][a-z0-9_\-]*', package_name_regexp = '[a-z0-9_][a-z0-9_\-]*',
package_uri_regexp = new RegExp('^https?://.*?(' + package_name_regexp + ').js$', 'i'); package_uri_regexp = new RegExp('^https?://.*?(' + package_name_regexp + ').js$', 'i');
package_name_regexp = new RegExp('^' + package_name_regexp + '$', 'i'); package_name_regexp = new RegExp('^' + package_name_regexp + '$', 'i');
window.iodide = new IODide(); window.iodide = new IODide();
props.py_cell_list = [];
IODide.prototype.addOutputHandler = function () { /*
function executePython() {
var queue = new RSVP.Queue(), i, len = props.py_cell_list.length;
queue.push(function () {
return initPyodide();
})
.push(function () {
for (i = 0; i < len; i += 1) {
executePyCell(props.py_cell_list[i]._line_list);
}
})
.push(undefined, function (error) {
console.log(error);
});
return queue;
}
*/
IODide.prototype.addOutputHandler = function() {
return; return;
}; };
function sideEffectDiv(sideEffectClass, reportSideEffect) {
// appends a side effect div to the side effect area
var div = document.createElement("div");
div.setAttribute("class", sideEffectClass);
if (reportSideEffect === undefined) {
div.setAttribute("style", "display:");
}
document.body.appendChild(div);
return div;
}
/*
function sideEffectDiv(sideEffectClass, reportSideEffect) { function sideEffectDiv(sideEffectClass, reportSideEffect) {
var div = document.getElementById(py_div_id_prefix + py_div_id_count_2), var div = document.getElementById(py_div_id_prefix + py_div_id_count_2),
pre = div.getElementsByTagName('pre')[0], pre = div.getElementsByTagName('pre')[0],
...@@ -65,6 +95,7 @@ ...@@ -65,6 +95,7 @@
} }
return div; return div;
} }
*/
// Copied from jio // Copied from jio
function ajax(param) { function ajax(param) {
...@@ -125,6 +156,50 @@ ...@@ -125,6 +156,50 @@
return null; return null;
} }
function preloadWasm() {
// On Chrome, we have to instantiate wasm asynchronously. Since that
// can't be done synchronously within the call to dlopen, we instantiate
// every .so that comes our way up front, caching it in the
// `preloadedWasm` dictionary.
let promise = new Promise((resolve) => resolve());
let FS = pyodide._module.FS;
function recurseDir(rootpath) {
let dirs;
var entry;
try {
dirs = FS.readdir(rootpath);
} catch {
return;
}
for (entry of dirs) {
if (entry.startsWith('.')) {
continue;
}
const path = rootpath + entry;
if (entry.endsWith('.so')) {
if (Module['preloadedWasm'][path] === undefined) {
promise = promise
.then(() => Module['loadWebAssemblyModule'](
FS.readFile(path), {
loadAsync: true
}))
.then((module) => {
Module['preloadedWasm'][path] = module;
});
}
} else if (FS.isDir(FS.lookupPath(path).node.mode)) {
recurseDir(path + '/');
}
}
}
recurseDir('/');
return promise;
}
function pyodideLoadPackage(names) { function pyodideLoadPackage(names) {
// DFS to find all dependencies of the requested packages // DFS to find all dependencies of the requested packages
var queue, toLoad, package_uri, package_name, k, var queue, toLoad, package_uri, package_name, k,
...@@ -179,7 +254,9 @@ ...@@ -179,7 +254,9 @@
} }
delete pyodide.monitorRunDependencies; delete pyodide.monitorRunDependencies;
packageList = Array.from(Object.keys(toLoad)).join(', '); packageList = Array.from(Object.keys(toLoad)).join(', ');
resolve("Loaded " + packageList); preloadWasm().then(() => {
resolve(`Loaded ${packageList}`)
});
} }
}; };
...@@ -241,6 +318,9 @@ ...@@ -241,6 +318,9 @@
current_type = next_type; current_type = next_type;
current_text_list = []; current_text_list = [];
} else if (current_text_list !== undefined) { } else if (current_text_list !== undefined) {
if (current_line.indexOf("matplotlib") !== -1) {
is_matplotlib_used = true;
}
current_text_list.push(current_line); current_text_list.push(current_line);
} }
} }
...@@ -414,6 +494,7 @@ ...@@ -414,6 +494,7 @@
function loadPyodide(info, receiveInstance) { function loadPyodide(info, receiveInstance) {
var queue = new RSVP.Queue(); var queue = new RSVP.Queue();
queue.push(function () { queue.push(function () {
return ajax({ return ajax({
url: "pyodide.asm.wasm", url: "pyodide.asm.wasm",
...@@ -432,7 +513,36 @@ ...@@ -432,7 +513,36 @@
return queue; return queue;
} }
function renderPyCodeblock(result_text, index) {
if (result_text !== undefined) {
var index_pos, index, code_text, div, pre, result;
index_pos = result_text.indexOf('_');
index = parseInt(result_text.slice(0, index_pos));
result_text = result_text.slice(index_pos + 1, -1);
div = document.getElementById(py_div_id_prefix + index);
pre = div.getElementsByTagName('pre')[0],
result = pre.getElementsByTagName('code')[0];
// py_div_id_count_2 += 1;
result.innerHTML = result_text;
}
}
function renderCodeblock(result_text) { function renderCodeblock(result_text) {
var div = document.createElement('div'),
pre = document.createElement('pre'),
result = document.createElement('code');
div.style.border = '1px solid #C3CCD0';
div.style.margin = '40px 10px';
div.style.paddingLeft = '10px';
if (result_text !== undefined) {
result.innerHTML = result_text;
pre.appendChild(result);
div.appendChild(pre);
document.body.appendChild(div);
}
/*
if (result_text !== undefined) { if (result_text !== undefined) {
var div = document.getElementById(py_div_id_prefix + py_div_id_count_2), var div = document.getElementById(py_div_id_prefix + py_div_id_count_2),
pre = div.getElementsByTagName('pre')[0], pre = div.getElementsByTagName('pre')[0],
...@@ -441,6 +551,7 @@ ...@@ -441,6 +551,7 @@
py_div_id_count_2 += 1; py_div_id_count_2 += 1;
result.innerHTML = result_text; result.innerHTML = result_text;
} }
*/
} }
function addPyCellStub() { function addPyCellStub() {
...@@ -551,21 +662,31 @@ ...@@ -551,21 +662,31 @@
// empty block, do nothing. // empty block, do nothing.
return; return;
} }
addPyCellStub(); var queue = new RSVP.Queue();
if (!is_pyodide_loaded) { if (is_pyodide_loaded === false) {
props.queue = new RSVP.Queue() // worker.postMessage("pyodide.asm.wasm");
.push(function () { if (is_matplotlib_used === false) {
worker.postMessage("load pyodide");
} else {
queue.push(function () {
return initPyodide(); return initPyodide();
}) })
.push(function () { .push(function () {
return pyodideLoadPackage('matplotlib'); return pyodideLoadPackage('matplotlib');
}); });
}
is_pyodide_loaded = true; is_pyodide_loaded = true;
} }
props.queue.push(function () { if (is_matplotlib_used === true) {
queue.push(function () {
return executePyCell(cell._line_list); return executePyCell(cell._line_list);
}); });
return queue
} else {
addPyCellStub();
}
return; return;
} }
return executeUnknownCellType(cell); return executeUnknownCellType(cell);
...@@ -577,8 +698,51 @@ ...@@ -577,8 +698,51 @@
}; };
} }
function collectPyCell(cell) {
if (cell._type === 'code_py') {
if (cell._line_list.length === 0) {
// empty block, do nothing.
return;
}
var i = 0,
len = cell._line_list.length;
for (i = 0; i < len; i += 1) {
if (cell._line_list[i].indexOf("matplotlib") !== -1) {
is_matplotlib_used = true;
}
}
var code_text = cell._line_list.join('\n');
props.py_cell_list.push(code_text);
return;
}
return;
}
document.addEventListener('DOMContentLoaded', function () { worker.onmessage = function(event) {
console.log('Received message ' + event.data);
if (event.data == "pyodide loaded") {
var i = 0,
len = props.py_cell_list.length;
console.log(props.py_cell_list);
for (i = 0; i < len; i += 1) {
// the code text is like "1_import sys\n..."
// We want to pass the index to make sure the code blocks were executed in order
worker.postMessage(i + "_" + props.py_cell_list[i]);
}
} else if (event.data.indexOf('wasm_') == 0) {
props.response = event.data;
executePython();
} else {
console.log("Result");
console.log(event.data);
renderPyCodeblock(event.data);
}
// props.is_pyodide_loaded = true;
// props.response = event.data;
// executePython();
};
document.addEventListener('DOMContentLoaded', function() {
var jsmd = document.querySelector('[type="text/x-jsmd"]').textContent, var jsmd = document.querySelector('[type="text/x-jsmd"]').textContent,
cell_list = parseJSMDCellList(jsmd), cell_list = parseJSMDCellList(jsmd),
...@@ -588,14 +752,9 @@ ...@@ -588,14 +752,9 @@
for (i = 0; i < len; i += 1) { for (i = 0; i < len; i += 1) {
queue.push(deferCellExecution(cell_list[i])); queue.push(deferCellExecution(cell_list[i]));
collectPyCell(cell_list[i]);
} }
// Python packages loading and execution
queue
.push(function () {
return props.queue;
});
return queue return queue
.push(function () { .push(function () {
console.info('JSMD executed.'); console.info('JSMD executed.');
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment