Git Product home page Git Product logo

Comments (8)

maxwellflitton avatar maxwellflitton commented on June 15, 2024 2

@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.

Thomasdezeeuw avatar Thomasdezeeuw commented on June 15, 2024

I'm trying to implement a Future trait for a struct to keep polling a TcpListener 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 a main function, it works. However, it's as if no data will ever reach it if it's implemented in a Future 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 Futures (containing some sort of I/O source) to poll.

Hope this helps. If still have trouble, feel free to ask more questions.

from mio.

maxwellflitton avatar maxwellflitton commented on June 15, 2024

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.

Thomasdezeeuw avatar Thomasdezeeuw commented on June 15, 2024

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". Futures themselves are pollable, they don't run on their own.

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.

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.

maxwellflitton avatar maxwellflitton commented on June 15, 2024

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.

Thomasdezeeuw avatar Thomasdezeeuw commented on June 15, 2024

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:

Would be easier if you introduce it as such, I'm not familiar with smol.

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.

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.

Thomasdezeeuw avatar Thomasdezeeuw commented on June 15, 2024

@maxwellflitton any update on this?

from mio.

notgull avatar notgull commented on June 15, 2024

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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.