Comments (8)
@Thomasdezeeuw the future now works now I no longer have the if outcome == () {
in the code. It was a mistake I made when I thought I did something similar in previous working code and I didn't. @notgull Yes thanks, I remember you helping me out with this a couple of months ago. I don't know if you remember me but I'm writing the async Rust book for O'Reilly. smol
is an amazing way of teaching async. The reader gets to learn about how async tasks are processed. In the book readers are implementing a smol
runtime, then implementing their own task stealing, and different configurations of queues and threads. They then implement Hyper
into the runtime, and they then play with Mio
to poll some sockets.
The reader then explores Tokio, and then different design patterns and testing approaches to async in general. @notgull I really love the smol
eco system and how it's structured. I've got a presentation with some banks and smol
is what I'm going to talk about. We're also using smol
for the Rust key-value store at SurrealDB.
from mio.
I'm trying to implement a
Future
trait for a struct to keep polling aTcpListener
however, when I call the port, it prompts the poll to fire but it always prints out the"no events"
printout. If this code just runs in amain
function, it works. However, it's as if no data will ever reach it if it's implemented in aFuture
trait. Am I missing something fundamental?
You are missing something fundamental, I'm sorry to say quite a number of fundamental things. I highly recommend you read the Mio and Future
documentation. Start with the Mio guide: https://docs.rs/mio/latest/mio/guide/index.html and the Future
trait: https://doc.rust-lang.org/std/future/trait.Future.html.
Hopefully, after reading those you'll realise that Future
is not the place to call Poll::poll
. In fact the events returned by Poll::poll
are often used to determine what Future
s (containing some sort of I/O source) to poll.
Hope this helps. If still have trouble, feel free to ask more questions.
from mio.
Hey @Thomasdezeeuw thanks for the links but they're introductions and I'm struggling to understand my solution using them. From what I understand, futures get converted to runnable and set on a task queue to be polled until completed. For this code example, I used smol
, flume
for the queue, and futures_lite
to handle the blocking of the thread until the task is complete. In terms of Mio
from what I understand you can create an event loop (infinite loop), poll the socket (timeout is optional), and then process the incoming data and then return to the event loop. You can pass that data from the socket to be processed as a future to be processed on the task queue. However, if you poll the socket with a timeout, why can't the socket be polled in a future's poll method? Surely if the socket poll times out, the future's poll method results in a Pending
and the future just gets put back on the task queue to run the poll again. When I run it, I keep getting "no events"
printout every 5 seconds. It's just that when I send a request to the socket, I get the "no events"
printout the moment the data packet is sent to the socket. What's the underlying mechanism that's stopping the data from coming out of the poll? I've seen the main thread blocked by a server that then spins off incoming requests to the task queue multiple times with multiple different crates. I don't want to implement that. I'm just trying to get a poll working inside the future.
from mio.
Hey @Thomasdezeeuw thanks for the links but they're introductions and I'm struggling to understand my solution using them. From what I understand, futures get converted to runnable and set on a task queue to be polled until completed.
I don't know what you mean by "futures get converted to runnable". Future
s themselves are pollable, they don't run on their own.
For this code example, I used
smol
,flume
for the queue, andfutures_lite
to handle the blocking of the thread until the task is complete.
If you use smol
, would it be easier to use smol::net::TcpStream
?
In terms of
Mio
from what I understand you can create an event loop (infinite loop), poll the socket (timeout is optional), and then process the incoming data and then return to the event loop. You can pass that data from the socket to be processed as a future to be processed on the task queue. However, if you poll the socket with a timeout, why can't the socket be polled in a future's poll method?
If read the Future
does it says:
The core method of future, poll, attempts to resolve the future into a final value. This method does not block if the value is not ready.
The "does not block" part is important here because otherwise there is little point in using non-blocking I/O that Mio provides.
Surely if the socket poll times out, the future's poll method results in a
Pending
and the future just gets put back on the task queue to run the poll again. When I run it, I keep getting"no events"
printout every 5 seconds.
Are you also making TCP connections? Otherwise you'll get zero events (as nothing has happened). Poll:poll
will only return events for I/O sources that can make progress. Going off the example you provided in your initial post, you only register the TcpListener
, that type will only generate an event if one or more connections have been made to it.
It's just that when I send a request to the socket, I get the
"no events"
printout the moment the data packet is sent to the socket.
What is "a request", as TCP doesn't have the concept of a request.
Also you code does the following
if outcome == () {
Which is always true as () == ()
is always true. What you should do instead (and is explained in the getting starting guide here: https://docs.rs/mio/latest/mio/guide/index.html, which you clearly didn't read) is following
// Poll the OS for events, waiting at most 100 milliseconds.
poll.poll(&mut events, Some(Duration::from_millis(100)))?;
// Process each event.
for event in events.iter() {
// We can use the token we previously provided to `register` to
// determine for which type the event is.
match event.token() {
SERVER => loop {
// One or more connections are ready, so we'll attempt to
// accept them (in a loop).
match listener.accept() {
Ok((connection, address)) => {
println!("Got a connection from: {}", address);
},
// A "would block error" is returned if the operation
// is not ready, so we'll stop trying to accept
// connections.
Err(ref err) if would_block(err) => break,
Err(err) => return Err(err),
}
}
}
}
Btw the code above comes directly from the getting started guide.
What's the underlying mechanism that's stopping the data from coming out of the poll? I've seen the main thread blocked by a server that then spins off incoming requests to the task queue multiple times with multiple different crates. I don't want to implement that. I'm just trying to get a poll working inside the future.
Again. Please read the getting started guide, it's very helpful. Yes, it's an "introduction", but you clearly skipped over it before and need to read it (again).
from mio.
I don't know what you mean by "futures get converted to runnable". Futures themselves are pollable, they don't run on their own.
Yes, this is true, a Runnable
is a handle as denoted in the following from async_task
documentation:
A handle to a runnable task.
Every spawned task has a single Runnable handle, which only exists when the task is scheduled for running.
Method run() polls the task’s future once. Then, the Runnable vanishes and only reappears when its Waker wakes the task, thus scheduling it to be run again.
Dropping a Runnable cancels the task, which means its future won’t be polled again, and awaiting the Task after that will result in a panic.
If you use smol, would it be easier to use smol::net::TcpStream?
Yes, it would. In my initial post, I stated that:
I appreciate that there could be a more optimal implementation, I'm just using this for educational purposes.
I'm building an async runtime using smol
, then use Tokio
traits to integrate Hyper
into the smol
runtime, and now exploring how to integrate Mio
polling into the runtime. For web apps in general I just use the listeners that the frameworks or crates provide out of the box.
Are you also making TCP connections? Otherwise you'll get zero events (as nothing has happened). Poll:poll will only return events for I/O sources that can make progress. Going off the example you provided in your initial post, you only register the TcpListener, that type will only generate an event if one or more connections have been made to it.
Yes, in my initial post, I said the following:
If this code just runs in a main function, it works. However, it's as if no data will ever reach it if it's implemented in a Future trait.
If it's working in the main function instead of being polled in the Future
implementation, then I am making connections and sending data over.
Also you code does the following
if outcome == () {
Which is always true as () == () is always true. What you should do instead (and is explained in the getting starting guide here: https://docs.rs/mio/latest/mio/guide/index.html, which you clearly didn't read) is following . .
Thanks this is the problem. The future polling this TCP listener is now working. It of course exits once it's received a message which is what I was expecting, I'm merely exploring the different ways in which I can poll sockets. In my previous code where it was all running in main
, I didn't break the loop if if outcome == ()
, but I thought I did leading to the confusion. I'm now going to look into Waker. Thanks for your time I appreciate it.
from mio.
I don't know what you mean by "futures get converted to runnable". Futures themselves are pollable, they don't run on their own.
Yes, this is true, a
Runnable
is a handle as denoted in the following fromasync_task
documentation:
Would be easier if you introduce it as such, I'm not familiar with smol.
I'm building an async runtime using
smol
, then useTokio
traits to integrateHyper
into thesmol
runtime, and now exploring how to integrateMio
polling into the runtime. For web apps in general I just use the listeners that the frameworks or crates provide out of the box.
But smol is already an async runtime and so is Tokio. And Tokio uses Mio for it's I/O. So what you're trying to achieve doesn't make a lot of sense... You can look at smol and Tokio for inspiration to build an async runtime on top of Mio though.
from mio.
@maxwellflitton any update on this?
from mio.
If your goal is to integrate smol
into hyper
, you may be interested in this example: https://github.com/smol-rs/smol/blob/master/examples/hyper-client.rs
from mio.
Related Issues (20)
- compile time error inside `poll.rs` HOT 3
- poll: Optimize locks and allocations in the critical path
- Poll(2) implementation follow-ups
- Official ESP-IDF framework support HOT 3
- Make `CompletionPort` public? HOT 7
- Difference behaves between Linux and Windows HOT 2
- How to wait for a socket to be writable? udp / Interest::READABLE | Interest::WRITABLE HOT 6
- could not compile mio due to 44 previous errors HOT 3
- WakerRegistrar mentioned in comment is not present HOT 2
- Decide MSRV for v1 HOT 2
- Use rustix instead of libc HOT 2
- Document MSRV policy HOT 1
- Update socket types API to match std lib HOT 5
- unresolved imports in target xtensa-esp32-espidf HOT 7
- `syscall!` macros hide unsafe code HOT 2
- why is it possible to create a mio TcpStream from std TcpStream but going the other way around is unsafe? HOT 13
- peek blocks after read on windows HOT 7
- Poll changing interest of server socket on Windows HOT 1
- Cannot continue listen! HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from mio.