6 ms·
> Scratching my head about whether I can call this part of my code from an async function because it might do filesystem operations or make a blocking network r
by spoiler 4y ago
> Scratching my head about whether I can call this part of my code from an async function because it might do filesystem operations or make a blocking network request. If I can’t, jumping through hoops to spawn an async task that can.
If you have code that needs to wait on IO (regardless of how fast or slow it could be, the point is that it's not predictable), and want to call it from an async function, why not make that code an async function too?
If it's library code, than yeah I agree it can suck. I tend to wrap those in my own API instead of inline spawning. At least it localises the uglyness, and that approach tends to compose well for me in practice. It does require a bit more code though, but my business logic code and plumbing code end up being separated and as a result easie to maintain too.
> Oh, now everything has to be static.
I will grant you that the static lifetime is a bit confusing until it clicks, but the issue is often that people have a wrong intuition about what a static lifetime bound means because it's introduced a bit clumsily and glossed over in the book.
I agree that async blocks feel a bit "smelly" syntax wise (for lack of better word).
I feel like some of these are just async woes that aren't trivial to solve, but I'd be surprised if the language teams weren't aware of this already and working towards solutions for these things. Async is very much MVP-ish in Rust anyway
- dcow 4y agoThe core of the problem from my angle is that rust’s stdlib is not async safe. It’s literally incorrect to call parts of the Rust stdlib from async code and the language tells you nothing about this. It doesn't even say “this function blocks are you sure you want to call it?”. So yeah I’ve got a bunch of my own library code (and others’) that I wrote normally and then later wanted to call it from async code and it’s a big mess. c.f. Swift’s async/await impl. Swift solved a lot of these woes because it ships a stdlib and runtime that supports async code.
- brundolf 4y ago> rust’s stdlib is not async safe. It’s literally incorrect to call parts of the Rust stdlib from async code and the language tells you nothing about this. Can you get more specific about what goes wrong when you call certain parts of the standard lib from async code? This is the first I'm hearing about this, and I'm not fully clear on what you mean by "not async safe"
- herbstein 4y agoNot OP, but it won't yield to the runtime. This blocks the executing thread until the operation completes. That's the only sense in which the standard library isn't async safe. Additionally, according to a core Tokio developer, the time between .await calls should be in the order of 100s of microseconds at most to ensure the best throughput of the runtime.
- jamincan 4y agoIsn't that a bit different from it not being safe, though? Ill-advised perhaps, but not necessary unsafe.
- dcow 4y agoIf you make too many of these calls your program will stop executing until I/O becomes available because you've exhausted your execution threads. If I/O never comes, which is very possible especially over a network connection, then you're stalled. Same outcome as being deadlocked, essentially. I'd argue this is very much unsafe because it's not correct async programming and can cause really difficult to debug problems (which is the same reason we care about memory safety--technically I can access any part of the pages mapped to my process, it's just not advisable to make assumptions about the contents of regions that other parts of the program might be concurrently modifying). The fact that people have never heard of this or don't understand the nuance kinda proves the point (=. You should, ideally, have to opt in to making blocking calls from async contexts. Right now it's all too easy to stumble into doing it and the consequences are gnarly in the edge cases, just like memory corruption.
- brundolf 4y agoHmm. In the worst-case though, wouldn't it just be equivalent to a non-async version of the program? I.e. "blocking" is what every normal function already does. Blocking for IO might take longer, but again, that's what normal Rust programs already do. So to me it sounds like "not async-optimized" rather than "not async-safe" But none of that sounds anything like a deadlock, so maybe I'm missing some other aspect here As an aside: "safe" means a very specific thing in Rust contexts, so even if this is analogous to that (preventing a footgun that could have catastrophic consequences), it might be best to use a different word or at least disambiguate. Otherwise people will argue with you about it :)