I made a prototype/polyfill for composable, Preview 3-style async: https://github.com/dicej/isyswasfa
It's still very experimental (I just got composition working this afternoon), but it's rapidly approaching usability.
That is absolutely great!
that name is great :)
Interesting. How does it handle child components that call out to pollable::block
or poll::poll
? Would that be game-over for concurrency in the parent?
Dave Bakker (badeend) said:
Interesting. How does it handle child components that call out to
pollable::block
orpoll::poll
? Would that be game-over for concurrency in the parent?
Correct -- none of the components in a composition should do blocking calls, just like with e.g. async functions in Rust. In practice, they can probably write to stdout (which technically involves a call to blocking_write_and_flush
) since it won't block "much", but in general blocking hostcalls will block everything.
However, we do have a plan for composing async components with sync components (or more specifically, allowing async calls to synchronous, blocking, non-reentrant components). There's no way to do this with e.g. wasm-compose
since the component model has no way to express this (yet!), but we can do it in the host at runtime. That's what this item in the "Planned features" section of README.md is about:
Host-side code generation for bridging async and sync components using backpressure to serialize async->sync calls without blocking the caller
The idea is to allow the host to mediate access to a sync component, providing backpressure to any and all async components which have made calls into that sync component.
To clarify: this would be non-blocking backpressure -- i.e. the async component(s) would still be able to make progress on other things while await
ing the synchronous call. They can even make more calls to the same synchronous component concurrently, with the host serializing the calls automatically. The key to making that work would be to run each synchronous component in its own fiber, independent of the fiber running the async component(s).
I expect @Luke Wagner will have more to say about that during the async session at the contributor summit.
Alright. Got it.
Great work, BTw
@Joel Dice can you elaborate on this a tad: Host-side code generation for bridging async and sync components using backpressure to serialize async->sync calls without blocking the caller
from the readme?
no hurry, of course, just wanna be sure I know what you're saying about this.
@Ralph please see my response to Dave above and let me know if it needs more clarification
I'm looking forward to Luke speaking today, of course. THIS was the phrase I meant: since the component model has no way to express this (yet!)
. I'm assuming you mean the async work we'll need in the expressions the model supports....?
but in any case, I'll keep this in mind as luke's chat comes.....
but we can do it in the host at runtime
I think this is referring to wasmtime's trampoline async_support
, where "blocking" client calls are exposed as async to the host.
I think the main discussion about async, led by Luke, is tomorrow if I'm reading the agenda correctly.
The goal with isyswasfa
is to do as much as possible with guest- and host-side code generation to compensate for the lack of async support in the component model as it exists today. In the future, such hackery will not be necessary, and any component-model-capable host or composition tool will understand what it means to do an asynchronous call to a synchronous, non-reentrant component. For the time being, we need to build that on top of Wasmtime and it's fiber support, creating a fiber per synchronous component and communicating between them using e.g. async channels.
A few quick updates on isyswasfa
:
wasi:http@0.3.0-draft
wasi:http@0.3.0-draft
to demonstrate concurrent outbound requests, streaming and forwarding request and response bodies, etc.isyswasfa
-flavored wasi:http@0.3.0-draft
components using isyswasfa serve
; see the README.md for examples that use it.Next, I'll be shifting my focus to making isyswasfa
obsolete as quickly as possible by implementing proper CM async support in wasm-tools
, wasmtime
, etc, working with Luke to nail down the design details as necessary.
yeoperson work here, @Joel Dice
This is all unbelievably cool. :grinning:
Joel Dice said:
Next, I'll be shifting my focus to making
isyswasfa
obsolete as quickly as possible by implementing proper CM async support inwasm-tools
,wasmtime
, etc, working with Luke to nail down the design details as necessary.
I've been kinda half paying attention. Would you mind clarifying: is the general idea that this would theoretically be able to eventually be compatible with / make use of the core Wasm stack switching work, but for now not be blocked on any particular design emerging as the winner on that side of things?
My opinion is that the MVP for composable async should not require or make use of stack switching, hence the focus on stackless coroutines (which should cover Rust, Python, JS, C#, etc. but not e.g. Go or Java). Eventually, we'll obviously want to support stackful coroutines as well, but I don't think that needs to be part of an MVP.
@Luke Wagner has pointed out that we don't necessarily need to wait for core stack switching to provide stackful coroutines -- we just need language toolchains to support reentrancy (i.e. allow the host to create multiple stacks for a single instance and use those stacks to support multiple concurrent calls). Core stack switching would presumably allow guests to also create multiple stacks, but we don't necessarily need that here.
In a nutshell: I think we can do a lot with what toolchains produce today (i.e. non-reentrant modules), so we should go ahead and do that, and when toolchains start supporting reentrancy we'll be able to do even more.
Next, I'll be shifting my focus to making isyswasfa obsolete as quickly as possible by implementing proper CM async support in wasm-tools, wasmtime, etc, working with Luke to nail down the design details as necessary.
That's awesome! When do you expect there will be an experimental stream
type to try? I'd like that for a proposed API, and since preview 2 is already released, preview 3 would be the earliest possible point of inclusion anyways.
Tarek Sander said:
I'd like that for a proposed API, and since preview 2 is already released, preview 3 would be the earliest possible point of inclusion anyways.
As I understand it, there will be some backwards compatible 0.2.* versions with additional APIs before 0.3. Breaking changes would go in 0.3. That means there might be opportunities for new APIs before stream types are released.
Tarek Sander said:
That's awesome! When do you expect there will be an experimental
stream
type to try? I'd like that for a proposed API, and since preview 2 is already released, preview 3 would be the earliest possible point of inclusion anyways.
You can use stream<u8>
in isywasfa
today -- I had to implement (a polyfill of) it to support wasi:http@0.3.0-draft
. The isyswasfa
implementation is basically just syntactic sugar for wasi:io/streams@0.2.0#input-stream
, plus a polyfill for the planned stream.new
canon builtin which returns writable and readable handles as output-stream
and input-stream
instances, respectively. I.e. it's morally equivalent to what we're planning for real stream
s, modulo the use of isyswasfa
in the names of things. If desired, we could generalize that to support stream<T>
for arbitrary T
using the same approach I used to implement future<T>
for arbitrary T
: synthesize a resource type for each unique T
as needed.
But perhaps your question is not so much "when can I try this?", but rather "when can I use the real version, not the polyfill?". If so, the answer is: as soon as I've implemented it in wasm-tools
, wasmtime
, wit-bindgen
, which I'm planning to do over the next few months.
And yes, per @IFcoltransG's comment: I suppose we could theoretically start using stream<T>
, future<T>
, and APIs which are meant to be lifted/lowered async in WASI 0.2.x releases, as long as it's done in a backwards compatible way. I'm not sure what the implications are of using new CM features in a WASI 0.2.x release, though; at a minimum we'd need to educate users that such a release has extra host implementation requirements that did not exist when WASI 0.2.0 was released.
Yes, stream<T> is what it'd like to use. Would awaiting work for multiple streams at once, or only one?
Awaiting multiple streams concurrently would work just fine.
After trying out this out over the weekend, I'm also looking forward to a stream<T>
Mainline Go already uses multiple stacks per goroutine, separate from the wasm call stack. It should already be reentrant.
Cool - that's great news. Does it also support Cgo, and if so, how does the C side of things manage multiple shadow stacks (i.e. the places where stack-allocated objects whose addresses have been taken reside)?
It doesn’t interact with Cgo at all.
Note: you might need a specific fork of TinyGo to use the output of this at the moment. We hope to land Component Model and WASI Preview 2 support in TinyGo soon.
Hi there everyone , Is iasyswasma fs ready to use ?
I have a requirement to run concurrent programming on guest side in component model .
Also which is the most simple test case in rust-cases to understand how I can use the guest and host for concurrent processing on guest side ? @Joel Dice
I think the simplest example is round trip - I modified that example to get what I wanted to achieve . But got an error , I have filed an issue - https://github.com/dicej/isyswasfa/issues/4.
Can you guys help ?
Hi @Afshan Ahmed Khan. isyswasfa
is an experimental project which will become obsolete once proper async support has been added to the component model, which is what Luke Wagner and I have been working on (see my recent update here). Feel free to use it and report any issues you find, but keep in mind that I'll stop supporting it once the component model features are in a usable state.
Also note that you don't need isyswasfa
or CM async if you only need to run simple components (i.e. components which have not been composed with other components). Instead you can just use a WASIp2-compatible runtime such as https://crates.io/crates/wasi-async-runtime or https://crates.io/crates/spin-executor if you're using Rust for the guest (and componentize-py
has a built-in asyncio
event loop for WASIp2 if you're using Python).
I'll leave a comment on the issue you opened, but the short answer is that the component model currently disallows reentering a component, meaning you can't call a guest export from a host import called by the guest. That's true for synchronous functions in the component model today and will continue to be true (AFAIK) for asynchronous functions as well. It's an interesting use case, though, so I'll discuss some alternative approaches in the issue.
Last updated: Dec 23 2024 at 12:05 UTC