4 ms·
This is also a problem over in Python-land. One of the interesting approaches is automatically generating non-async code from async code by editing out the asyn
by geofft 6y ago
This is also a problem over in Python-land. One of the interesting approaches is automatically generating non-async code from async code by editing out the async annotations (at the source level). The Trio folks call this "bleaching" the code, in reference to the "What color is your function?" blog post https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/ https://journal.stuffwithstuff.com/2015/02/01/what-color-is-... complaining about how the common approach to async in JavaScript divides the world into "red" (async) and "blue" (sync) functions that interoperate poorly - you can bleach your code if it's the wrong color.
https://github.com/urllib3/urllib3/issues/1323 https://github.com/urllib3/urllib3/issues/1323 is a discussion of this. "Solution: we maintain one copy of the code – the version with async/await annotations – and then a little script maintains the synchronous copy by automatically stripping them out again. It's not beautiful, but as far as I can tell all the alternatives are worse.
https://github.com/python-trio/unasync https://github.com/python-trio/unasync is the current production implementation of this approach.
- kmeisthax 6y agoIn Rust, you don't need to do this. If you want a blocking version of a non-blocking function, you spin on poll. Several async libraries ship a block_on function that does just that. If you can't do that, but don't want to bring in a proper big-boy executor; you can spin off another thread, have it block, and join it when it's done. (or use something like crossbeam's scoped threads) Colored functions are a problem in JavaScript because it has to share an event loop with the rest of the browser. For Node.js and Python, that is less of an issue, but those languages are also either practically or actually single-threaded, which also means async behavior is contagious. Rust does not have this problem, at least not until you're writing WASM programs with it (in which case, you're restricted to sharing one thread with the rest of the browser again).
- geofft 6y agoWell, 'Animats expresses a desire in another comment for functions not to go off and spawn a new thread. I do somewhat agree with that desire - I don't think that this is a problem for performance, but since most of my use of Rust is dropping it into existing C code, I think that spawning a thread is likely to have annoying visible side effects on the calling code, which might not be expecting me to do that. Using a proper, single-threaded executor and running it on the current thread seems like it would work, yes. (To be fair, I also feel like just having the sync version of a Python API call "trio.run(self.equivalent_async_api)" would probably also work, and I don't totally follow why that's insufficient....)
- h0l0gr4ph1c 6y ago> "Using a proper, single-threaded executor and running it on the current thread seems like it would work, yes. (To be fair, I also feel like just having the sync version of a Python API call "trio.run(self.equivalent_async_api)" would probably also work, and I don't totally follow why that's insufficient....)" Why do I need all this other bloat just to run a function? Why can't I just run the function?
- geofft 6y agoI'm not sure exactly what you're asking, but I think it's either answered by the "What color is your function?" article I linked above, or by the answer that this is exactly why unasync exists and why I suggested that approach is worth considering, or by the answer that you can, in fact, just run the function and the "bloat" (which is just syntactic bloat - note that performance is generally going to be better!) is taken care of behind the scenes by a wrapper that calls an executor for you.
- h0l0gr4ph1c 6y agoyes sorry, those were rhetorical questions. Your point about asking you fail to see why not using a blocking executor to deal with the async code. My problem is with needing the executor at all. I must have skipped a couple of you previous pints in this thread. Apologies about that... Maybe we should start trying to think about async as being something can use if they want and ignore if they want. Code being async compatible rather than async required.
- pas 6y agoAs long as the async code doesn't depend on calling itself concurrently it should be straightforward to simply execute it on the current thread, right? (Basically using an executor that has 1 thread, the current thread.) And it'd be great to check and optimize away all this at compile time.
- geofft 6y ago
- lmm 6y agoIt's a problem if your function to query a database or whatever instantiates a bunch of futures and yields between them when you're just going to block. Given that Rust is designed for environments that are so limited that they can't afford garbage collection, that stuff is proportionately pretty costly.
- millstone 6y agoDoes spin-on-poll imply actual spinning (100% CPU) or actual blocking (waiting in a syscall)?
- dodobirdlord 6y agoThat would have to be determined at the discretion of the implementer of the library. Rust is after all capable of being used to write code that will run in a context where there is no kernel and thus no syscalls.
- millstone 6y agoI don't get it - what library? I may have an `async` function and this is part of the Rust language, not tied to any library. Can I make it into a blocking function without 100% CPU?
- pas 6y ago"async/await" is just syntactic sugar for a function that returns a Future plus a state machine at yield points. You need a library (executor) to run that Future (execute that function). The Rust standard library's block_on uses a global ThreadPool, and the docs recommend using a LocalPool if you need finer grained control. So, to answer your question it depends on the executor (the thing that implements block_on).
- steveklabnik 6y ago(To be clear, block_on is not in the Rust standard library.)
- pas 6y agoah, darn, thanks! So for anyone reading for the correct details: the block_on I was thinking of is part of the futures crate, which is not in std, it's not an "official library".
- lmm 6y agoWow. Reminds me of those go projects that use templated code with Canadian Aboriginal Syllabics to work around the lack of generics.