27 ms·
Tokio 1.0 – async runtime for Rust
- aliceryhl 6y agoThe changelog can be found here: https://github.com/tokio-rs/tokio/releases/tag/tokio-1.0.0 https://github.com/tokio-rs/tokio/releases/tag/tokio-1.0.0
- maxfurman 6y agoCongrats to the Tokio team! This is a big deal for the Rust ecosystem.
- seeekr 6y agoThey mention working on using io_uring for filesystem calls for 2021. I wonder if there will be an option to use io_uring (instead of epoll) for networking calls as well? Handling network packets and events completely in userspace should allow for lower latency due to no more context switches to and from the Kernel, right?
- carllerche 6y agoWe are definitely exploring this as well. There are a few possible ways to move forward on this. I'm not sure which is best yet, but with 1.0 out, we are going to be able to put more time into it.
- gaogao 6y agoThere's some interesting bits on the low-level work for using io_uring with the Ringbahn crate - https://boats.gitlab.io/blog/post/ringbahn/ https://boats.gitlab.io/blog/post/ringbahn/
- Smerity 6y agoThe author of sled[1], an embedded database in Rust which has a number of promising features, has also written parts of rio[2], an underlying pure Rust io_uring library, which is intended to become the core write path for sled. rio has support for files but also has a demo for TCP (on Linux 5.5 and later) and O_DIRECT. I tested rio recently as I had a Brilliant but Bad Idea™ involving file access and was pleasantly surprised by the API, as I have been with sled's. I'm excited for the experimentation in the Rust ecosystem and for such low level crates to handle the complex io_uring tasks (relatively) safely! [1]: https://github.com/spacejam/sled https://github.com/spacejam/sled [2]: https://github.com/spacejam/rio https://github.com/spacejam/rio
- pas 6y agoBoth epoll and io_uring depend on the kernel to do the "actual IO", if you want really user-space you need DPDK and a userspace network stack (for TCP/UDP). Both epoll and io_uring have virtually the same performance. Of course uring is a lot more "ergonomic" that's why it already has amazing momentum.
- anarazel 6y agoYou can do network IO completion notification, instead of readiness notification with io_uring but not epoll. Which avoids the need for a separate syscall that needs to copy memory into the userspace buffers. That can be noticable. It should also, at some point, allow for nice zero copy network receive paths under the right circumstances (i.e. the network card DMAing directly into the userspace buffers, without very weird setup/high op overhead).
- JT_Laos 6y agoAs someone who has criticized Rust for the small standard lib and lack of stability in the ecosystem I'm very, very happy for this. This is one of the biggest milestones for Rust. Rust itself is great enough. The lack of a de facto async runtime and libs for your standard networking needs were a real barrier for non-enthusiasts environments. It will help its adoption in general purpose business apps, I guess and hope.
- otachack 6y agoCongrats! I've fallen off Rust due to pivoting at work plus trying other languages but I'm intrigued again by Tokio's announcement. I'll be trying out your tutorial soon!
- edulix 6y agowhat did you pivot to and why, if you don't mind me asking?
- echelon 6y agoYour comment was "dead", but I see nothing wrong with it and vouched for it. This is a valid question asked earnestly. I'd honestly like to know too.
- kiadimoondi 6y agoCan't speak for the commenter, but I used to work for a team couple years ago that used rust and tokio extensively, and some projects were just not a good fit. At the time, futures were well fleshed out but the community hadn't caught up, so we were lacking a futures-compatible postgres and redis client. We wrote the redis client ourselves, and for the main project using rust that was sufficient. But for postgres, that was a show stopper for any other projects we were working on. So we ended up deciding between typescript and go for those.
- ibraheemdev 6y agoThe ecosystem has moved forward a lot since then. Pretty much all IO libraries provide an asynchronous API now.
- sanxiyn 6y agoNote: now tokio-postgres works fine.
- johnsoft 6y agoJust curious, did you consider wrapping the existing sync clients with something like spawn_blocking[1]? If so, what tradeoffs did you find? [1]: https://docs.rs/tokio/1.0.0/tokio/task/fn.spawn_blocking.html https://docs.rs/tokio/1.0.0/tokio/task/fn.spawn_blocking.htm...
- pfraze 6y agoCan someone explain to a non-rustacean what Tokio introduces that's not part of Rust? It looks like Rust provides the async/await semantics, so I'm guessing this is an event loop and dispatching system?
- pfraze 6y agoReplying to myself, I found this bit in the docs explaining how Tokio decorates the main: > An async fn is used as we want to enter an asynchronous context. However, asynchronous functions must be executed by a runtime. The runtime contains the asynchronous task scheduler, provides evented I/O, timers, etc.
- steveklabnik 6y agoTo provide some more color on why this isn't built in, different runtimes provide different kinds of guarantees and performance profiles. A webapp has very different requirements than an embedded system, and so we don't want to provide a single runtime. The language contains the basic things needed for the ecosystem to exist, and interoperation points, and then leaves the rest to said ecosystem. (Some of those interoperation points are still being worked out, so it's not perfect yet.)
- pfraze 6y agoAs always, very elegant. Thanks for the added info.
- steveklabnik 6y agoYou're welcome, thanks :) If you want to dig deeper: * https://www.infoq.com/presentations/rust-2019/ https://www.infoq.com/presentations/rust-2019/ * https://www.infoq.com/presentations/rust-async-await/ https://www.infoq.com/presentations/rust-async-await/
- olalonde 6y agoWhen learning Rust a few months ago, I built a small client library for a REST API using reqwest (which uses Tokio). I then started writing a web app using Tide (https://github.com/http-rs/tide https://github.com/http-rs/tide). I eventually realized that it would be difficult to use the library I had built earlier since Tide uses the async-std runtime rather than Tokio. That was very disappointing. Is there any plan to make it easier to write "runtime agnostic" libraries in the future?
- worik 6y agoThe first two paragraphs have a lot of guarantees. About stability of version 1.0, length of support for version 1.0 and how long until version 2.0 (at least). "We "we are committing to providing a stable foundation..." I am curious: Who is "we"? I have no priors, I really have no idea.
- ibraheemdev 6y agoThe tokio maintainers and contributors
- worik 6y agoWell obviously, but that is not really an answer. Perhaps it is not answerable but it is a important question, when guarantees are made, who is making them? I am not sure it is a important question in that it is not a important guarantee. The software is what it is, it is open and modifiable. But if the guarantee mattered then this would be a crucial question and the answer would describe the organisational structure of the "tokio maintainers and contributors" as a group
- aliceryhl 6y ago"we" here refers to the Tokio team.
- urza 6y agoWhat would be Tokios equivalent in .net/C# ?
- deleted 6y ago[deleted]
- steveklabnik 6y agoThe direct equivalent is the async runtime part of the .net/C# runtime, that is, it's built-in there, but is a library here.
- Xevi 6y agoC#/.NET has all of this already. You don't have to import anything else to use async/await.
- dragonwriter 6y ago[deleted: man, was that a dumb comment]
- jayd16 6y agoNo I think you're mistaken. You can rewrite pretty much every part of the system. You can write your own synchronization, you can write your own scheduling, you can write custom awaiter implementations. Its very pluggable. You might be able to argue that its even more pluggable than Tokio because the system has the concept of current context and attaching a task to it. Library code can use your custom scheduler. You can even throw away the Task type and create your own future type that works with the async/await syntax but of course no library would be able to pick that up.
- tick_tock_tick 6y agoOf course it does just because C# comes with all the bells and whistles doesn't mean you can't write your own in it. https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.taskscheduler?view=net-5.0 https://docs.microsoft.com/en-us/dotnet/api/system.threading...
- ibraheemdev 6y agoToday also saw the release of Hyper 0.14, the HTTP client built on top of Tokio [0] [0]: https://news.ycombinator.com/item?id=25521217 https://news.ycombinator.com/item?id=25521217
- boulos 6y agoNow hyper-tls and hyper-rustls need updating :).
- rossmohax 6y agoIt is unfortunate, that libraries have to be coded against specific runtime and not generically. There is tokio and there is smol (likely discontinued, since author left rust), maybe other runtimes will emerge, but whole ecosystem is already tied to tokio.
- ibraheemdev 6y agoasync-std [0] is pretty widely used as well. [0]: https://github.com/async-rs/async-std https://github.com/async-rs/async-std Most libraries can be used with different runtimes. Hyper for example, which uses Tokio by default, can be configured to use an async-std executor.
- mmastrac 6y agoI always get a weird vibe from async-std. I respect the people working on it, but it feels like it's trying to boil the ocean. I'd be very interested in hearing other opinions, as my Rust project [1] is currently stuck on an older version of Tokio while I wait for deps to update. I'm either going to have to bite the bullet and replace deps or bite more bullets and find a different runtime. [1] https://github.com/mmastrac/stylus/ https://github.com/mmastrac/stylus/
- rossmohax 6y agoCan't find async-std feature here: https://github.com/hyperium/hyper/blob/master/Cargo.toml https://github.com/hyperium/hyper/blob/master/Cargo.toml do you have an example? Either way, "can be configured" means that custom code for each runtime must be written, it is not like lets say "Futures", which can be used generically.
- sorenbs 6y agoIs it a concern that both Tokio and stdlib have AsyncRead+AsyncWrite traits that seem to be incompatible?
- sanxiyn 6y agoYes, it is a concern, but Tokio people decided transition can happen without breaking changes hence it does not block 1.0. See https://github.com/tokio-rs/tokio/issues/2716 https://github.com/tokio-rs/tokio/issues/2716 for details.
- sorenbs 6y agoThank you!
- lights0123 6y agoRust doesn't have AsyncRead+AsyncWrite in std. You may be thinking about the third-party futures crate though, which does have a currently incompatible implementation.
- jgilias 6y agoHuge thanks to all the contributors! I've been using Tokio in a few projects and it has been a very good experience. Also thank you all for the welcoming community. I once posted on Tokio's Github about a quirky (in my eyes) behavior of a particular edge case and got an answer almost in real time. This really makes Tokio a kind of a project where I could see myself contributing if an appropriate opportunity arises. Thanks again! Looking forward to all the good things still in the pipeline!
- jhgg 6y agoCongratulations on 1.0! Tokio and the ecosystem surrounding it (tracing, hyper, prost, tower) are incredibly well thought out and a pleasure to use for building fast performant services with solid latencies.
- mkl95 6y agoI have known Tokio for ages and I'm not even a Rust programmer. It seems like a solid project.
- xucheng 6y agoI wonder whether there is any ongoing effort to unify the ecosystem between different runtimes. Specially considering that Tokio and futures (by extension async-std) implement their own Async* traits, it seems that it becomes even harder to write runtime agnostic libraries. It would be nice if these fundamental traits were part of rust std library.
- steveklabnik 6y agoThis is mentioned downthread, but yes, the intention is still for that to happen. There's more work to be done here.
- baby 6y agoCan someone tell me why tokio is so damn big and full of transitive dependencies :D?
- ibraheemdev 6y agoYou could also say that Tokio has a large and mature ecosystem surrounding it.
- geodel 6y agoHow big is it?
- octoberfranklin 6y agoHere are the compiled-in dependencies: $ cargo tree -e no-dev,no-build --no-dedupe -p tokio tokio v1.0.0 ├── bytes v1.0.0 ├── libc v0.2.81 ├── memchr v2.3.4 ├── mio v0.7.6 │ ├── libc v0.2.81 │ └── log v0.4.11 │ └── cfg-if v0.1.10 ├── num_cpus v1.13.0 │ └── libc v0.2.81 ├── once_cell v1.5.2 ├── parking_lot v0.11.1 │ ├── instant v0.1.9 │ │ └── cfg-if v1.0.0 │ ├── lock_api v0.4.2 │ │ └── scopeguard v1.1.0 │ └── parking_lot_core v0.8.2 │ ├── cfg-if v1.0.0 │ ├── instant v0.1.9 (*) │ ├── libc v0.2.81 │ └── smallvec v1.4.2 ├── pin-project-lite v0.2.0 └── signal-hook-registry v1.3.0 └── libc v0.2.81 There are a lot more dependencies that are used only for the build scripts (build-dependencies) or for running the tests, examples, and benchmarks (dev-dependencies). None of those dependencies cause any additional code to wind up in your binaries when your project depends on tokio. PS, I think there's a bug in "cargo tree"... the command above actually prints out only one line ("pin-project"). I had to remove the "-p tokio" and then copy-and-paste out the relevant section.
- simias 6y agoI don't really get these modern async APIs. In languages like Javascript I thought they only made sense because JS interpreters are (historically) single-threaded, so you really have no choice but async to express some concepts. Fine. But in Rust you can just spawn threads, share data through channels or mutexes, use OS-provided async IO primitives to poll file descriptors and do event-driven programming etc... I tried looking into Tokio a little while ago and I found that it led to some incredibly complicated, abstracted, hard to think about code for stuff I usually implement (IMO) much more simply with a basic event loop and non-blocking IO for instance. I'm sure async can get the upper hand when you have a huge number of very small tasks running concurrently because that's generally where OS-driven parallelism tends to suffer but is it such a common scenario? That sounds like premature optimization in many situations IMO. Unless you actually think that async code is more expressive and easy to read and write than basic event loops, but then you must be a lot smarter than I am because I have to take an aspirin every time I need to dig into async-heavy code. I guess I'm trying to understand if it's me who's missing something, or if it's web-oriented developers who are trying to bring their favourite type of proverbial hammer to system development.
- jayd16 6y agoMaybe its a matter of taste but I find async styles much easier to read than event driven coding.
- sanxiyn 6y agoComparison is to threads, not to event callbacks. Threads are (at least in Rust) even easier to read than async.
- artursapek 6y agoIt's syntactic sugar that makes code a lot easier to reason about.
- sanxiyn 6y agoSynchronous code is even easier to reason about than code using async syntax sugar.
- cbdumas 6y agoThis is awesome, thanks to all contributors to this incredible tool!
- rustytherust 6y agoWhat happened to go?! Did it become as rust will?! Obnoxious and pretty useless? Anyway glad rust is catching up with other languages. Async, boy this the future.
- rognjen 6y agoI find the domain amusing: https://en.m.wikipedia.org/wiki/Srbija_do_Tokija https://en.m.wikipedia.org/wiki/Srbija_do_Tokija
- ComputerGuru 6y agoOne of the issues I have with the rust async story is that colored functions require (at least the way they’re handled in rust and similar languages) a separate standard library (Microsoft really outdid themselves providing a synchronous and asynchronous version of the BCL when they shipped async support, but that was also largely made possible by the fact that the underlying OS APIs were all fairly asynchronous at the lowest levels and had that asynchronocity exposed/available all the way through the BCL for C# devs already). One problem with this is that an api like tokio’s might appear to be asynchronous but in reality portions of it are “just” synchronous API calls marshaled to a thread pool - i.e. none of the real benefits of async for now, but positioned so that the library can be switched over to real async code and automatically take all the consumers with “it in the future.” I’m glad to hear mention of io_uring because it means that IOCP on Windows might get some love. For those that don’t know, on Linux there is^H^H was really no such thing as properly async file system access (eg libc faked it in a similar fashion for aio) so libraries like mio didn’t bother with true async for non-network parts of the library (and also partially because the biggest motivation for async development was the web world which doesn’t particularly care about asynchronously listing the contents of a directory or writing a “highest” performance backup product) - even though at least some platforms (like Windows) had very compelling async options available across the board.
- anarazel 6y ago> For those that don’t know, on Linux there is^H^H was really no such thing as properly async file system access (eg libc faked it in a similar fashion for aio) That's not quite right - there didn't use to be AIO for buffered filesystem IO and for most operations beyond read/write. But unbuffered reads/writes have been doable asynchronously for quite a long time, via io_submit/libaio. Without falling back to threads. The restrictions around that can be onerous (e.g. one needs to be careful to not extend file sizes, or risk falling back to synchronous operation).
- habitue 6y ago> there didn't use to be AIO for buffered filesystem IO Did they change libaio to work without O_DIRECT at some point? Or are you talking about io_uring for async file io?
- renewiltord 6y agoAlways found these APIs a little hard to work with. For instance, if I tried to use `actix-web`, then using `reqwest` and `tokio` felt like pulling teeth. If anyone's got minimal code lining up a web framework (any one, not stuck to actix) with some reqwest, I'd be thankful to look over it. Just some trivial stuff so I can add an API gateway that proxies a specific API.
- jayy-lmao 6y agoI've got a few examples of simple web servers within my company, could backport some of it to a public example. Are you just looking to have something a bit like: ``` #[get('/todo')] async fn getTodos(...) -> impl Responder { let todos = reqwest.get('other-api/todos').await?; todos } ``` Obviously this code won't run, just want to gleam the gist of what you want from an example.
- renewiltord 6y agoHey, thank you for offering. Yes! Something minimal like that that doesn't use `reqwest::blocking` would be very helpful. If it could do the Error case too that would be cool. For Rocket, I have something like: #[get("/list/<status>")] fn list_prospects(api_key: ApiKey, status: String) -> Result<Json<PendingList>, Status> with a impl<'a, 'r> FromRequest<'a, 'r> for ApiKey But I couldn't quickly get an `async` piece in there so I just sucked it up and synced it all up since it's only backing a Retool dashboard so it isn't the end of the world. So if the example is like: #[get('/todo')] fn get_todos() -> Result<Json<TodoList>, Status> let todos = reqwest... Ok(todos) or the equivalent in the web framework you have that would be hecka useful.
- nicoburns 6y agoFor Rocket you want to use the master branch which has async support. Then your request handler is an async function and you can just .await the future returned by reqwest.
- 6y ago
- olliej 6y agoIt irks me that the "async runtime" isn't simply part of the rust runtime. Making it be a separate library simply increases the likelihood of having to deal with libraries expecting different version, or even different async runtimes entirely.
- octoberfranklin 6y agoRust doesn't have a runtime. That's part of its awesomeness. That's why it can target microcontrollers. You're probably used to languages with garbage collectors. Having garbage collection forces you to have a "runtime" since that's where the GC code goes. Then more and more stuff accretes onto this unavoidable runtime, and before you know it you're writing Java code...
- olliej 6y agoUm, rust does have a runtime, that's why you don't need to include packages for strings, refcounting, allocation, etc. Anything that has a language keyword should have a default implementation in that runtime, and much like box, ?, !, etc async and await are both language features that I shouldn't need to include from outside of the runtime.
- ibraheemdev 6y agoWhat the OP is probably referring to is that Rust does not have a runtime in the typical sense used by languages such as Java. Rust does have a runtime, as all non-assembly languages do, but it is very very small. Languages with minimal runtimes like C or Rust are commonly referred to as having "no runtime".
- GolDDranks 6y agoThose are all pay-as-you go features; in my mind I associate runtime with a single, constant-ish initialization cost, plus possibly some background processing or inserted hooks that do janitor work for you. Rust doesn't have a runtime in that sense.
- octoberfranklin 6y ago
- ben0x539 6y agoIt's getting close to the point where I can't make my "semver just means prefixing your version number with `0.`" joke anymore. :< Congrats to the tokio team + contributors. <:)
- boulos 6y agoI'm hopeful that this leads to some focus on the ergonomics of "waiting for async things from sync code". Lots of "handlers" in the universe have synchronous interfaces, so if you want to implement them you end up needing to poll/wait on async from a regular function. I swear that every time I poke at Rust, I seem to find some way to cut my fingers... My specific example is writing a fuse handler (now with cberner/fuser formerly zargony/rust-fuse) for GCS/S3. If you want to use make any async requests (like via hyper), you currently have to roll your own poller, like reqwest does in blocking mode [1]. The rust async/.await primer [2] offers the reader the seemingly helpful futures::executor::block_on, but basically no two executors can interact (and for good reason!). As others highlight, the ecosystem seems like it's going to end up standardizing on tokio (and/or some flavor thereof) and that hopefully now that it's 1.0, we can have stable enough deps for a while :). [1] https://github.com/seanmonstar/reqwest/blob/5ee4fe5ab64a2e3d81efb9540cb9bdb98b8d6938/src/blocking/wait.rs#L10 https://github.com/seanmonstar/reqwest/blob/5ee4fe5ab64a2e3d... [2] https://rust-lang.github.io/async-book/01_getting_started/04_async_await_primer.html https://rust-lang.github.io/async-book/01_getting_started/04...
- vlmutolo 6y agoI've encountered the "wait on async things from sync code" issue several times, too. I have found that something like `block_on` from either `futures` or `futures_lite` often does the trick. https://docs.rs/futures-lite/1.11.3/futures_lite/future/fn.block_on.html https://docs.rs/futures-lite/1.11.3/futures_lite/future/fn.b...
- boulos 6y agoRight, but depending on the tokio version (maybe) using block_on results in a hang or panic. I’ll see if futures_lite is any different, but I think it’s mostly on tokio’s side.
- masklinn 6y ago> depending on the tokio version (maybe) using block_on results in a hang or panic Isn't it mostly a function of what runtime you're using? `block_on` with a single-threaded runtime can't run tasks elsewhere (since there's only one thread which you're blocking) so depending on the version it would either hang (before detection of that situation was added) or panic, with an error message saying to use a multithreaded runtime. I completely agree that it's a pain in the ass though, especially since there are situations where tokio must be coerced into using anything but the basic scheduler (e.g. tests).
- diveanon 6y agoI really like writing rust, however not having the async runtime be a part of std has hurt the language in my opinion. Crate consumers have to consider which async lib a crate is using leads to a lot of annoying gotchas that can really confuse less experienced rust devs. I'm hoping tokio becomes the default and eventually gets merged into std, it really is the best async implementation.
- deleted 6y ago[deleted]
- swsieber 6y agoCool stuff. There seems to be some cool improvement every several months. I'm excited for GATs to land so we can have true async trait methods. The async story in Rust has come a long way, but there's still a lot to be improved.
- volta87 6y ago> Also, Tokio would not have been possible without Aaron Turon's and Alex Crichton's early involvement. This feels like a slap in the face for some reason. Aaron Turon is an extremely talented individual (their PhD thesis was a landmark contributionn). They are super kind and one of the nicest human beings I've ever met. They led the Rust Project until their involvement with Tokio caused them to drop off from Tech. Alex Crichton is an extremely talented, kind, and hyperproductive individual, who after their involvement with Tokio dropped all async/await work and luckily "refocused" on WebAssembly. If one is going to recap the road towards Tokio 1.0 and mention all the people that have left the Rust async ecosystem or Rust all together, you might as well spell things out.
- Ygg2 6y agoWhat? Why did they drop from tech? Are you sure this isn't something else instead?
- tobz 6y agoDoesn't seem very productive to speak on behalf of two folks who you clearly don't have the authority to speak on behalf of. ¯\_(ツ)_/¯
- volta87 6y agoI don't speak on behalf of them, I saw this on Twitter back when it happened, e.g., check Aaron Turon's twitter feed from back then.
- dboreham 6y agoThere seems to be some time loop with network application concurrency approaches. I began my career re-writing servers that had a non-blocking socket model with a state machine to use threads, so we could understand and maintain the code now that OS vendors had come around to supporting threading widely. Fast forward a few decades and the world is teeming with smart people who seem to think it's a good idea to go the other way..
- heavenlyblue 6y agoWhat you were looking though was a syntax to program those things rather than the specific implementation.
- tinynation 6y agoThis is awesome, congrats on the 1.0! As a new rustacean it was really difficult to try and use the the async/await syntax with horde of adapters required for tokio 0.1/0.2. I ended up trying out async-std too, but the move to smol had its own issues and I lost interest. A 1.0 release with stability commitments is exactly what I need to get back into experimenting with Rust.
- bfrog 6y agoI see a lot of hate for what amounts to user controlled and scheduled tasks. Do people understand that async/await is effectively user land task scheduling, which for any high performance networking app is of vital importance. Consider cassandra versus scylladb