Pyodide 0.24 is a major release focused on fine tuning public APIs and
performance. It includes a major rework of the streams APIs to be faster and
more flexible. We increased the consistency of the foreign function interface.
We also added micropip
support for the Python simple repository API.
Performance Improvements
Up to this point, we had not devoted much energy to performance improvements so there were many low-hanging fruit.
Loading performance
We finally added a packages
argument to loadPyodide
so that packages can be
downloaded during the Pyodide bootstrap. We also fixed the problem that
pyodide.asm.wasm
only began downloading after pyodide.asm.js
was finished
loading. Loading them simultaneously can improve the load time by as much as a
second depending on network conditions. There is a lot more work to do in
improving load time but both of these changes are significant improvements.
Foreign Function Interface performance
Several major bottlenecks were identified. The biggest performance problem was
with the hiwire map. This map is needed because C cannot directly handle
JavaScript references, only numbers. To pass JavaScript values through C, we
place the JavaScript values into a map and pass the index of the map into C. The
process of inserting and removing JavaScript values from the hiwire map was
taking almost all of the execution time in some profiles. By changing the data
structures involved we managed to improve the performance of to_js
by a factor
of 15 on a 10kb json object.
Also, rendering the error messages for PyProxy
use-after-free errors takes a
huge percentage of the runtime in some use cases. We fixed this by pregenerating
the strings involved and interning the results, and by only enabling more
detailed error messages if pyodide.setDebug(true)
is run first.
As another time saver, we avoid registering PyProxy
arguments with the
FinalizationRegistry
unless necessary. FinalizationRegistry.register
and
FinalizationRegistry.unregister
are expensive calls and in some cases we know
the PyProxy
is automatically destroyed by the Pyodide foreign function
interface so these calls can be avoided.
Streams Rework
The internal implementation of the pyodide.setStdxxx
APIs was completely
reworked. It is now faster and allows correct handling of keyboard interrupts
and O_NONBLOCK
/ EAGAIN
. We also added a new way of implementing standard
streams by defining a read
function for stdin
or a write
function for
stdout/stderr. These are the simplest APIs to implement internally, and the
older APIs are implemented in terms of them.
micropip improvements
We’ve made some useful improvements to micropip.
Simple Repository API support
micropip now supports the Simple Repository API (PEP 503, PEP 691), which is a
standard way of querying packages to the Python package repository. We also
added supports for using package repositorys other than PyPI via
micropip.install(index_urls="...")
or micropip.set_index_urls()
. This means
that you can host and use a collection of webassembly-emscripten Python packages
that you have built in your local environment, using
pyodide build.
Other API improvements
It is now possible to remove packages at runtime using micropip.uninstall
.
We also added the verbose
option to micropip.install
. Previously, micropip
was totally silent and it was hard to tell which versions of which packages were
being installed from which indices. Now, when run in verbose mode, pip-like
installation messages are printed to stdout.
For a detailed list of changes, see the v0.24 changelog.
What’s next
- Recently clang and Emscripten have added much better support for
externref
. Usingexternref
s will allow further performance improvements and a significant reduction in code size. - Chrome is going to have origin trials for JavaScript Promise Integration in the next few months. Once available in browser engines, the JSPI should solve many of our I/O woes. We have already done a lot of work on JSPI support for Pyodide and are hoping to include a mature implementation in the next release.
- Cibuildwheel support and a PEP for Emscripten wheels on PyPI support.
- More work on load time and ffi performance.
Acknowledgements
Thanks to everyone who contributed code to this release and all users who reported issues and provided feedback. Thanks to the PyScript and Jupyterlite developers and community for their feedback and contributions. Particularly, we would like to thank Andrea Giammarchi, Antonio Cuni, Chris Laffner, and Der Thorsten. Thanks to Brett Cannon and Mark Shannon for core Python support.
Thanks to the Emscripten team for their helpful and responsive support.
The following people commited to Pyodide in this release:
Adam Tombleson, Alexey Ignatiev, Andrea Giammarchi, Angus Hollands, Arpit, Bart Broere, Christian Clauss, chrysn, David Lechner, Deepak Cherian, Eli Lamb, Feodor Fitsner, Guillaume Lemaitre, Gyeongjae Choi, Hannes Krumbiegel, Hanno Rein, Henry Schreiner, Hood Chatham, Ian Thomas, Jeff Glass, Jo Bovy, Joe Marshall, Joseph Rocca, Juniper Tyree, Kai Tietz, Kevin Hill, Loïc Estève, Luiz Irber, Maks Bialas, Martin Renou, Martoxa, messense, Michael Weinold, Milan Raj, nascheinkman, Neil Stoker, Nicholas Bollweg, Owen Lamont, Ralf Gommers, Roman Yurchak, Tamás Nepusz, TheOnlyWayUp, Tim Paine, Tim Sherratt, Tomas R, Tom Nicholas, Victor Blomqvist, Yan Wong, Ye Joo Park, Yossi Shirizli, कारतोफ्फेलस्क्रिप्ट