Feature: Run pyodide in worker
Checklist
- [X] I added a descriptive title
- [X] I searched for other feature requests and couldn't find a duplicate (including also the
type-featuretag) - [X] I confirmed that it's not related to another project area (see the above section)
What is the idea?
It would be nice if you could make pyscript code run in a worker.
Initially without DOM integration, but could add DOM integration via a proxy potentially...
Why is this needed
Personally I like this, because I could move all my testing scripts over to pyscript for things that are supposed to finally run in jupyterlite.
It would be nice generally though if pyscripts didn't hang the browser when doing long running tasks.
What should happen?
I envisage an attribute, so you could do e.g.
<py-script worker="true">
for c in range(1000):
do_something_slow()
</py-script>
without hanging the browser.
Alternatively, it could be a global option to make all pyodide on a page run in a single worker.
A super cool addition to this feature would be to make a proxy for the main thread js object, so it could still access DOM etc., although I think that probably requires either a) cross site isolation or b) stack switching proposal support to come into browsers, so that normal postmessage / comlink can be used for async calls.
Additional Context
No response
FTR, I have a prototype (and a video walkthrough) re-imagining PyScript in a direction like this. It's too radical a step for this narrow ticket. But I wonder if you'd like to collaborate on kind of an explainer-style series. (I'll do most of the work if you'd like.)
I guess @tedpatrick can offer some context on this also. :)
I love the idea of <py-script> attributes to define main/web-worker/sync/async behavior of script content. As to the names/api/behavior... that will take some time to define. This is an important use case to work through and get right. Part of the core planning after the 2022.09.1 release is to really sharpen our focus on what we want PyScript to be in time. We are starting to define that 🧭 heading now.
Thought sample... 🤔
<py-script></py-script> < ! ╌ defaults to main + sync ╌>
<py-script async></py-script> < ! ╌ defaults to main + async ╌>
<py-script worker></py-script> < ! ╌ defaults to worker + sync ╌>
<py-script worker async></py-script> < ! ╌ defaults to worker + async ╌>
Is that async as in javascript scripts? i.e. with that syntax, by default it downloads the python, loads the interpreter and holds up the rest of the page until that is done? I think that's bad if so - unless the interpreter startup speeds up massively, holding up the page load for interpreter load would be not good I think.
If it is as in runPythonAsync / runPython, I think that async isn't a good name because it is the same word as async as in javascript tags, but it means something different. Also if it is this, why does py-script need a separate async/non-async version? If you don't use any awaits in your code, then runPythonAsync does roughly the same as sync give or take package loading (which either a) does nothing, or b) is needed for the code to run)?
I think for me, the biggy is what to do about the js object when pyscript is run in a worker. Should there be a document proxy, and if so, how the heck does it work (threads, stack-switching, ...) If crossSiteIsolation is enabled it is trivial. If the stack-switching proposal (or the call promises proposal) finally gets accepted and into browsers, it is also pretty easy. But until then there is going to be real limits to what you can do without enabling crossSiteIsolated, which is a pain.
@joemarshall I'd agree with you:, using the async as a keyword for a py-script tag is probably not the right thing, since as you say it doesn't necessarily mean the same thing as async in a script tag - from discussions elsewhere, I believe the thought is to use it in the sense of` runPython/runPythonAsync.
A more accurate (but wordier) version of the keyword might be allow-top-level-await, since that's the core difference between the two. (I think you already know this, but including it here for the purposes of general discussion, since there's been confusion around what runPythonAsync does.)
-
runPython doesn't allow top level await - it compiles the code and
eval()'s it -
runPythonAsync compiles code with PyCF_ALLOW_TOP_LEVEL_AWAIT enabled,
eval()'s it and, if the result of eval is a coroutine, awaits that coroutine.
Discussion is now centralized here: https://github.com/pyscript/pyscript/discussions/1113 We're making a lot of progress regarding webworkers, we'll soon have something :) probably next or the nextnext update. Thanks for chiming in folks, feel free to join the current discussion.