X Tutup
The Wayback Machine - https://web.archive.org/web/20250605064734/https://github.com/RustPython/RustPython/issues/5435
Skip to content

Make the runtime interruptible (similar to await/yield) #5435

Open
@kawogi

Description

@kawogi

Summary

Make it possible to return from a VM even though the script in there is still not complete.

Expected use case

We're running RustPython within a WASM module in a WebWorker, so it's essentially running in it's own dedicated thread. The Script therein has the capability to send messages to other WebWorkers via channels and other WebWorkers can send back their responses. The Responses will normally trigger an event handler (onmessage) in the Webworker so that the messages can be processed.

Due to the single-threaded nature of JavaScript that event handler will never be executed unless we give back control to the underlying runtime. In our case the would mean we need to somehow return from the WASM-call and thus interrupting the running Python VM.

Possible approaches

I could imagine three ways to support temporary interruption:

Preemptively

After calling enter the underlying VM executes a bunch of instructions (maybe a fixed number or with a timeout) and returns with a value indicating the execution is not complete and can be resumed (e.g. a continuation token). The caller can then perform other duties and resume the execution later (e.g. by calling a new resume-method)

Cooperatively

The Python code can call some built-in function (e.g. await, yield) allowing the VM to return in mid-execution. Otherwise this is the same as above

async

The enter-method becomes async and calls into a #[pyfunction] will be async as well. This is similar to the cooperative approach, but permits easier integration with Rusts async ecosystem

Alternatives

I'll continue my research whether this can be solved without altering RustPython. So far I could think of the following workarounds:

  • maybe wasm_bindgen supports some feature to interrupt the execution of a WASM module in a way that makes it possible to temporarily yield to the JavaScript-Runtime.
  • Instead of using JavaCript-Channels I could try to build my own data-exchange framework based on SharedMemory and Atomics. So far this has been an ergonomic nightmare but it should work in theory.
  • Use multithreading in WASM. Last time I tried this I ended up with a very fragile setup that was very hard to run reliably. The ergonomics from the Rust side would be very good, though. Maybe things have improved in the meantime.

Here is an example how wasmtime solves this: https://docs.rs/wasmtime/latest/wasmtime/struct.Config.html#method.consume_fuel

BTW: thanks a lot for this awesome crate ❤️ impressive work!

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions

    X Tutup