5 ms·
Your comment touches on a few misconceptions I see a lot. Firstly, `reqwest` exposes both an async and a synchronous API, allowing the developer to choose whic
by songqin 6y ago
Your comment touches on a few misconceptions I see a lot.
Firstly, `reqwest` exposes both an async and a synchronous API, allowing the developer to choose which one to use. They are largely interchangeable code-wise. [1]
Secondarily, and more broadly, async is possible to opt out of. You must understand that most web and network related libraries will be async by default for performance, because people who write in Rust and people who write web servers typically care greatly about performance. This is the intersection of those two groups. That being said, there are options outside of that ecosystem. [2]
If you truly want to use an asynchronous library without migrating your application to run entirely on an async runtime like tokio, you can run it inside of a synchronous function without much trouble. I've put together a playground link for you. [3]
1. https://docs.rs/reqwest/0.11.2/reqwest/blocking/index.html https://docs.rs/reqwest/0.11.2/reqwest/blocking/index.html
2. Iron: https://github.com/iron/iron https://github.com/iron/iron
Rouille: https://github.com/tomaka/rouille https://github.com/tomaka/rouille
3. https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=fac87a37c5d29b3342b41d7c8ed015d3 https://play.rust-lang.org/?version=stable&mode=debug&editio...
- Animats 6y ago"reqwest" exposes a synchronous API, but it's doing async stuff underneath. If you turn on logging, you can see 30 or so async events associated with a single HTTP client side request. It's starting up and shutting down a polling thread just to make one HTTP client request. You must understand that most web and network related libraries will be async by default for "performance". That's what scares me - async contamination of the low level Rust ecosystem. The async enthusiasts have to be kept in check to prevent breaking Rust as a systems language.
- songqin 6y agoI had understood your concern as wanting to avoid the complexity of asynchronous code execution in your codebase, I did not realize your concern is about writing very low level systems code. In that case, you are doing the right thing: libraries like ureq, minreq, Isahc, curl, and more all offer what you want. It is unclear to me what you mean by keeping the community "in check". There are a lot of people who rely on and enjoy the async story, and they will continue to produce code that improves that story. Simultaneously, there are people who do not need that, and they are not hindered by this. People will build what they want and need. You've just picked some libraries from some of the biggest async contributors in the community and requested that they be kept in check so that you don't have to switch to a synchronous alternative, of which there are plenty.
- AgalmicVentures 6y agoYou're replying to John Nagle, as in https://en.m.wikipedia.org/wiki/Nagle%27s_algorithm https://en.m.wikipedia.org/wiki/Nagle%27s_algorithm -- perhaps it would be worth considering his words further, before dismissing his concerns? Surely we can all agree that spinning up unnecessary threads is undesirable?
- bobthebuilders 6y agoAppeal to authority fallacy
- deleted 6y ago[deleted]
- woah 6y agoDoesn’t matter who he is, if he’s mad that libraries made for and by web and network developers are using a concurrency model that works well for their applications, he should use different libraries.
- AgalmicVentures 6y agoIt does matter -- he was one of the first "network developers". He published RFC 896 over 35 years ago; he has more experience on this topic than almost anyone. > Please respond to the strongest plausible interpretation of what someone says, not a weaker one that's easier to criticize. Assume good faith. This is not the strongest plausible interpretation of what he said -- He's not asking for people to not develop async code. He's asking for them to not hide it in synchronous code. If you're expecting a blocking system call, and actually get a brand new background thread that's polling, it's quite reasonable to be frustrated.
- cycloptic 6y ago>If you're expecting a blocking system call, and actually get a brand new background thread that's polling, it's quite reasonable to be frustrated. It really isn't if the documentation doesn't outright say that it's single threaded and not thread safe. For a lot of simpler use cases where you just want to ship a thread-safe API (e.g. application does not have its own thread pool) then it just makes sense in a lot of cases to use some kind of automatic thread pooling. The caller does not have to know or care how the internal state machine is implemented. If you have implemented your own thread pool it seems you should know enough to dig down enough to the lower layers to where you can get to that blocking syscall, or least to the point where you can strip off the O_NONBLOCK flags yourself.
- jjtheblunt 6y agoExactly
- geofft 6y agoLet me try to rephrase this in a way that doesn't pin the blame on "async enthusiasts" as people, and see if you agree: Many years ago, well before Rust 1.0, Rust used its own M:N threading system, used segmented stacks, had it's own libuv-based event loop, etc. Also, it had garbage collection built into the language. These were removed before 1.0, which made Rust a lot better as a systems language: you could reliably embed it into non-Rust programs, you could reliably interoperate with non-Rust libraries that didn't expect to be moved around threads, you didn't need to care about starting up the GC (or handling GC pauses), etc. This was a good decision for Rust, and it turns out most of the things people wanted to do with these features could be done outside it - e.g., the borrow checker avoided the need for pervasive GC. (Though almost certainly not intentional, one side effect is that it distinguished Rust from Go: Go is great for standalone programs that need lightweight concurrency, but it's very bad at being embedded into other code and not the best choice if you're mostly calling FFI libraries.) First, it would be good for Rust to stick to that decision. Rust should not regain a pausing GC in the standard library - similarly, it should not regain a thread manager in the standard library. Second, it would be good for Rust libraries to work within the spirit of that decision. That's a lot harder, because part of the expectation when those features were removed was that some needs - notably around event-based processing - would be met by third-party libraries. As I understand it (and I might be totally wrong!), it was honestly a bit of luck that the borrow checker worked as well as it did and was ready at the right time, and the expectation was that someone would add a GC library and it would be widely used. However, it's very good that no widely-used GC library sprung up. In the same vein, it would be good for there to be no widely-used third-party thread manager library. This might be hard, possibly requiring a borrow-checker-level miracle, but it's worth aiming for. And if there has to be a thread manager (or a garbage collector), it should not be part of core Rust. Would you agree with that phrasing? -- Incidentally, why does reqwest start up a polling thread when called in sync mode? Can't it do the polling on the main thread? (Or in other words, async programming doesn't imply multithreaded programming. I actually sort of expect that async programming is better suited to single-threaded programming with an event loop, because if you're okay with threads, you may as well just write synchronous code on threads! So either there is something subtle and very interesting here, or there's an easy fix, or I'm misunderstanding something badly.)
- 6y ago
- cycloptic 6y agoThat doesn't seem to be related to async? I don't know the details of rust's async implementation but that sounds like a problem with your application's setup -- you should be able to have a single threaded async executor that uses an event loop, or in simple cases, just calls poll/select directly? To put it another way, it's unfortunate that particular synchronous API is implemented using threads, but there is nothing about async that implies one way or another that a synchronous method will be implemented using threads -- I've seen plenty of (questionable) C functions that do similar things like using pthread_create and then pthread_join immediately after to fake a blocking task.
- ori_b 6y agoEr? No, the point is that threads are what you want for cpu-bound tasks. Async does not deal well with long running cpu intensive jobs that hog the cpu without yield points.
- cycloptic 6y agoWhy not? The fix there sounds like it's as simple as adding some yield points.
- ori_b 6y agoYield points in the middle of a large matrix multiplication (for example)? Manually scheduling threads seems like a really shitty way to program
- cycloptic 6y agoNot really? That's cooperative multitasking and it's used a lot: https://en.wikipedia.org/wiki/Cooperative_multitasking https://en.wikipedia.org/wiki/Cooperative_multitasking But regardless, the GP post was not taking about matrix math, it seems it was talking about sending an HTTP request and waiting for a response, which is something that actually is I/O bound on the TCP socket.
- deft 6y agoNo, its not a misconception. It still uses tokio. It still triples my compile time.
- h0l0gr4ph1c 6y agoComplexity kills code. Being able to reason about what your code is doing, is FAR more valuable to me than async. Having tokio act as my runtime and switch tasks as it sees fit will be debug hell. The problem I see is the current async story is opt-out. It's use async or go find something else. Async should be opt in. As in, the code works regardless of an async runtime, async is added magic if you want it, but it will run like normal single threaded code if not.
- Animats 6y agoThe problem I see is the current async story is opt-out. It's use async or go find something else. Async should be opt in. That sums this discussion up nicely.
- songqin 6y ago> The problem I see is the current async story is opt-out. Surely this is only the case if you have picked asynchronous libraries to use?
- steveklabnik 6y agoYes, in fact, you cannot even use async Rust without writing your own executor or bringing one in via a library. It is very, very much opt in. That was a hard constraint on the design. However, I think what the parent is getting at is the feeling of the total package, not the technical details. If every library you want to use is async, you can't really "opt out" exactly, even if technically the feature is opt out.
- h0l0gr4ph1c 6y agoBy opt in I mean I can opt in to using an executor if I want async. If I don't code still works and is might not be as performant. Couldn't you have made another hard constraint to make async code work as normal if the programmer wanted?
- steveklabnik 6y ago