5 ms·
TRust-DNS: implementing futures-rs and tokio-rs support
- Perceptes 10y agoGreat article. Very thorough. I'm really looking forward to Hyper (and in turn, Iron, or whatever replaces it) being rebuilt on futures-rs and Tokio. I'm eager to start using this approach in my HTTP programs.
- bluejekyll 10y agoYeah. It looks like it's under progress, I'm really excited for HTTP futures as well. It will make it exceptionally easy to build highly performant web servers.
- steveklabnik 10y agoIt is! https://github.com/hyperium/hyper/tree/tokio https://github.com/hyperium/hyper/tree/tokio
- parley 10y agoIt would be so great if Sean got to work full time on hyper, but of course I understand that he is needed elsewhere at Mozilla and he's doing a great job with the time he has. I would hazard a guess that there are so many besides me waiting for the upcoming HTTP client/server improvements that it would probably not be the worst idea if Mozilla (or some other org betting on Rust) threw some money at it. I'm extremely grateful to everyone working on Rust and its ecosystem (paid or otherwise) for the work that you do. It sure sounds cheesy, but after trying lots of stuff over the years, Rust feels like coming home. There, I said it. I'm pushing it at my employer, and for every piece of tooling or important crate that matures, it gets easier to evangelize.
- steveklabnik 10y agoYeah, I hear you. That said, money is being thrown, but at tokio itself, rather than at hyper. You have to finish the lower bits before the higher ones. (also, <3)
- bluejekyll 10y agoYes, I've been evangelizing Rust at work as well. We're making a big push to SOA, so I'm using it as an opportunity to inject new things.
- pimeys 10y agoI'm in a lucky position to be able to choose the tools I use at work. For certain parts, Rust's been already a great help and right now I wait tokio and hyper/tokio more than I waited for Super Nintendo when I was a child. They will be an enormous help when refactoring the current services. I'm pushing myself to learn more so I could be helping with these projects. That said, thank you for the whole Rust team. It hits the sweet spot being fast, not eating so much memory, being pleasure to write and having amazing tooling around it.
- Perceptes 10y agoSean (or other Hyper maintainers), if you're reading this, it'd be really useful to have a tracking issue for the Tokio integration rather than just a branch. I'd like to be able to subscribe to something to keep track of progress and discussion on the topic!
- steveklabnik 10y agoSo! To recap the bits, and where this all stands now: The end goal is to implement "Your Server is a Function" https://monkey.org/~marius/funsrv.pdf https://monkey.org/~marius/funsrv.pdf , that is, built on top of three primitives: 1. Futures 2. Services, which are functions of Request -> Future<Response> 3. Filters, which takes a Request and a Service, and returns a Future<Response> To do this, Tokio is built up of multiple packages that each have a focus. At the lowest layer, you have two primitive libraries: futures and mio. Futures are a generic, no-allocation abstraction that looks something like this: https://docs.rs/futures/0.1.6/futures/future/trait.Future.html https://docs.rs/futures/0.1.6/futures/future/trait.Future.ht... pub trait Future { type Item; type Error; fn poll(&mut self) -> Poll<Self::Item, Self::Error>; } ... and a bunch of more interesting methods built on top of poll. Futures, as you can see, can be generic over the kind of value they produce, as well as possible errors while producing said value. poll drives the future forward, and should never block. Usually, you don't call poll directly, you create a Task, which represents a chain of futures, and tell it to run. It will then handle doing the right thing, calling the right methods in the right ways. The second component is mio. Mio is a low-level, asynchronous I/O library, that gives you the standard event loop stuff. In other words, it's a very thin wrapper around epoll/kqueue, and has an adapter to make iocp fit. There are deeper reasons that readiness was chosen over completion as a model, but I won't get into that right now. So, the lowest layer of tokio proper is tokio-core, which combines futures and mio to give you the ability to say "give me an event loop. Chain some futures together. Run this chain on the event loop." But that's still a fairly low-level interface. And it's what's being shown off here. At the same level, tokio-service is what gives you the Service abstraction. At the sort of middle layer, there's a bunch of libraries that you can use, like tokio-proto, which gives a slightly higher-level interface for implementing network protocols. Finally, the unreleased tokio package combines this ecosystem into an easy to use way to build servers, it's the whole package. This "tons of tiny packages" approach means that if you want to extend tokio in some way, you pick the appropriate level of the stack for your task, and plug it in, and everything up the chain can benefit. It's very modular and extensible. In graphical form, check out this image: https://twitter.com/rustconf/status/774734062636249089 https://twitter.com/rustconf/status/774734062636249089 which comes from this talk: https://www.youtube.com/watch?v=bcrzfivXpc4 https://www.youtube.com/watch?v=bcrzfivXpc4 The key enabler here is Rust's zero-cost abstractions: last time we measured, tokio-core had a very small (less than half a percent, IIRC) overhead compared to writing a mio event loop by hand. And that's before significant profiling effort has been done. So while in many languages, all of these layers would add up to significantly reduced speed, the idea here is that in Rust, they won't. A significant portion of this is zero-allocation or single-allocation, for example.
- IshKebab 10y agoThe thing I don't get is why Rust sockets have a `set_nonblocking()` function at all. Should there just be separate`recv_blocking()` and `recv_nonblocking()` functions? It would be much simpler. Sadly you can't even do your own interface like that because there is no `get_nonblocking()` function. Also is HN ever going to support markdown?
- steveklabnik 10y agoThe standard library's abstractions tend to be relatively thin mappers over OS functionality: https://doc.rust-lang.org/stable/std/net/struct.UdpSocket.html#method.set_nonblocking https://doc.rust-lang.org/stable/std/net/struct.UdpSocket.ht... So, in my understanding, it has this interface because that's the interface that the OS gives you. Why couldn't you write this interface on top? You'd be writing that function yourself, no?
- valarauca1 10y agoIn Unix you don't get a choice to block on one or the other. You just get a non-blocking File Descriptor. To add this you'd need to iron bandage system calls during compilation depending on which calls were made, and their order they were made. The alternative is having an Epoll/Kqueue loop run until one or another happen. But that's still a lot of magic and resource consumption behind the scenes for a language that offers low level control.
- markdog12 10y agoAny chance Rust is going to get async/await keywords?
- steveklabnik 10y agoIt's quite possible! And even if it doesn't, approaches like https://github.com/erickt/stateful https://github.com/erickt/stateful might work as well.