-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Result is a bit misleading #3
Comments
Hi, thanks for the comment. I took at look at your benchmark, and I think we are measuring different things. My goal was to understand the overhead of doing I/O. In a real app, doing I/O requires managing poller registrations and making I/O syscalls, and having tasks suspend and wake, which I don't see in your benchmark. Basically I wanted to make sure these things could be handled efficiently, by having poller registrations live across multiple awaits and avoiding I/O calls on objects known to not be ready. Fortunately, this turned out to be true. Nothing about Rust async forces the developer to make extra syscalls compared to a hand-written poll loop. A fair amount of "accounting" code is needed to achieve this though. So the other thing I was trying to understand was the minimum cost of such accounting (both for the I/O stuff and the executor/wakers). This is why I make my own executor and fake I/O objects. I am aware of mio, and in fact my fakeio module uses a similar interface. And while I agree tokio is the most mature runtime, I suspect it would have more overhead. My executor is very minimal, no heap, no Arc. I am fairly confident my measurements show the minimum overhead of async I/O. In practice with normal runtimes, the overhead will likely be higher. |
Indeed, we are measuring different things. |
I like the idea of comparing to tokio. I'd need to think about how to do it though. My implementation runs the I/O reactor and executor in the same thread. |
Tokio runtime has a current thread mode, which can be of use here.
…------------------ Original ------------------
From: Justin Karneges ***@***.***>
Date: Mon, Apr 5, 2021 0:03 AM
To: jkarneges/rust-async-bench ***@***.***>
Cc: QiuJiangkun ***@***.***>, Author ***@***.***>
Subject: Re: [jkarneges/rust-async-bench] Result is a bit misleading (#3)
I like the idea of comparing to tokio. I'd need to think about how to do it though. My implementation runs the I/O reactor and executor in the same thread.
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub, or unsubscribe.
|
Yes, but I don't see a way to specify where to run the reactor code. Basically, I need to run Otherwise, all I can think of is:
Probably the latter approach is the most practical. It would add some overhead, but it's closer to how tokio is meant to be used. |
I discovered that the The main change to the code I had to make was to use Some numbers, with
As expected, the futures-rs executor is a little slower. My guess is this is mostly due to its use of Box when spawning, and perhaps a little bit due to using Arc for waking. Boxing futures is a very reasonable to do, though. AFAIK tokio does it too. Trying to avoid that (as my executor in this repo does) would be impractical in most real apps. |
Thanks for following up.
You can implement Future trait for FakeReactor and call waker.wake_by_ref() before returning Poll::Pending in FakeReactor every time. let f = do_async(spawn, ctx, reactor, stats, AsyncInvoke::Connection(stream)); What's the intention of passing in ctx and reactor? AFAIK, if you implement a future, ctx will be passed automatically. In a well-designed async funtion, you don't have to pass ctx and reactor maunually |
The problem with trying to put the reactor in a future is it needs to run only after all other futures have reported pending. It might be possible to relax this requirement by refactoring the fakeio module. The reason ctx and reactor are passed is to avoid using thread local storage. This is because the code avoids threading primitives. I don't know if thread local storage has overhead or not, though. If it doesn't, perhaps it could be used. |
The benchmark result just scared me. I was quite afraid of the overhead of async. For me, even 1 us is an eternality. However, I made my own benchmark
As the result suggests, there is about 1.5 ns's performance panelty per
async
/await
.I think there's a few flaws with your method.
glommio
.The text was updated successfully, but these errors were encountered: