Skip to content
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

Demo using warp #91

Open
joshtriplett opened this issue May 7, 2020 · 15 comments
Open

Demo using warp #91

joshtriplett opened this issue May 7, 2020 · 15 comments

Comments

@joshtriplett
Copy link
Contributor

I managed to run warp in smol, quite easily:

use warp::Filter;

fn main() {
    for _ in 0..num_cpus::get() {
        std::thread::spawn(|| smol::run(futures::future::pending::<()>()));
    }

    smol::block_on(async {
        let hello = warp::path!("hello" / String)
            .map(|name| format!("Hello, {}!", name));

        warp::serve(hello)
            .run(([127, 0, 0, 1], 8080))
            .await;
    })
}

Please consider adding this as a demo.

@Stupremee
Copy link

Why do you spawn some threads at the beginning that will just execute the pending future?

@tekjar
Copy link

tekjar commented May 7, 2020

@Stupremee That's how multi threaded runtime is setup in smol. I haven't gone through the internals yet but smol has work stealing which distributes tasks to these threads

@szagi3891
Copy link

szagi3891 commented May 8, 2020

This is amazing. I switched a few lines and my project using wrap and it just started :)

@csarn
Copy link

csarn commented May 8, 2020

For me it panics at
there is no reactor running, must be called from the context of Tokio runtime

it seems to come from hyper::server::tcp::AddrIncoming::from_std calling something from tokio.
How would I address that?

@llebout
Copy link
Contributor

llebout commented May 8, 2020

@csarn See here: https://github.com/stjepang/smol/blob/master/examples/hyper-server.rs

hyper uses tokio internally by default, this uses an interface that hyper offers for runtime-agnostic operation, to use hyper (which warp uses) with smol.

@llebout
Copy link
Contributor

llebout commented May 8, 2020

@joshtriplett I think your example still uses Tokio under the hood. So you are running Tokio AND smol, which is not great. You would need to intialize the HTTP server with a custom acceptor that uses smol like explained in my previous comment. I am not sure if warp supports that though.

@szagi3891
Copy link

@csarn
does your dependence to "smol" look like this?
smol = { version = "0.1", features = ["tokio02"] }

@csarn
Copy link

csarn commented May 8, 2020

@szagi3891 ha thanks, I didn't see that part of the README :) I looked at the github repo a while back when the README was still empty, and didn't think of looking again...
Now it works.

EDIT: I'm quite new to this async topic, can someone explain what advantage one could get from using smol, when there's still tokio under the hood somewhere, vs. when there was a way to use "pure" smol without any tokio?

@szagi3891
Copy link

With smol you can run code that uses async-std and tokio libraries. For me, this is the most appealing feature.

Here is more explained by the author:
https://stjepang.github.io/2020/04/03/why-im-building-a-new-async-runtime.html

@llebout
Copy link
Contributor

llebout commented May 14, 2020

@csarn @szagi3891

If you run a library with an explicit dependency on Tokio with smol, there's clearly no advantage to use smol. The tokio compatibility layer is provided to help migration but it's clearly expected for libraries to become runtime-agnostic. Running two runtimes in the same program is undesirable, unless used temporarily until migration happens, it's not great.

As specified in my previous comment, you need to look at warp to see if they provide a custom acceptor and spawner interface like hyper. This interface allows to get rid of the tokio dependency even though it still depends on Tokio's AsyncRead and AsyncWrite traits and a compat layer with the futures crate's AsyncRead and AsyncWrite traits, Tokio wont be running as a runtime and that's good.

See demo with hyper server and custom acceptor/spawner here: https://github.com/stjepang/smol/blob/master/examples/hyper-server.rs

You need to seek for a similar interface in Warp.

The problem currently is an eco system one, Tokio used to be the only runtime so agnosticity was not a concern. Tokio have their own AsyncRead and AsyncWrite traits because they say futures crate one are inefficient, w.r.t. it having default implementations of vectored read and write operations encouraging people to never implement them and w.r.t. using uninitialized memory buffers that do not need to be zero-initialized for no reason besides safety. Tokio made the bytes crate to cope with safety of uninitialized memory but that's mostly a Tokio-only crate at this point. There's work by the Rust language devs to provide better mechanism to use uninitialized memory safely, it'll come out eventually. The result is that Tokio has adopted in-house solutions to these problems because they have an apparent pressing efficiency and performance need without waiting for the language to evolve towards them which means for the people who chose to rely on more official means of doing async Rust to future proof their applications, Tokio becomes kind of a separate eco system and garden on its own. Until recently, there was no easy AsyncRead/Write compatibility layer between Tokio and Futures (official) crate. The situation is a bit better now that there is, and smol uses that compatibility layer, but there's still the problem of Tokio primitives like timers that applications use and that have an explicit dependency on a running Tokio runtime, and they don't provide runtime agnostic interfaces for that, which effectively locks any Tokio user into Tokio for now.

@zicklag
Copy link

zicklag commented Jun 9, 2020

I opened an issue in Warp to ask about this: seanmonstar/warp#601.

@llebout
Copy link
Contributor

llebout commented Jun 23, 2020

@zicklag seeing that they closed your issue I encourage you fork and modify this file:

https://github.com/seanmonstar/warp/blob/master/src/server.rs

You can inspire yourself from the hyper server example here:

https://github.com/stjepang/smol/blob/master/examples/hyper-server.rs

@zicklag
Copy link

zicklag commented Jun 23, 2020

Oh, great. Thanks for the pointer. I was wondering about that, but I needed a hint in the right direction. If anybody else wants to try it first, I'm not sure when I'll get to it. 😃

@kvsari
Copy link

kvsari commented Nov 17, 2020

I'll give this a shot. It looks like adding an extra method like this one.

I imagine some extra parameters to be sent such as the spawner to be used as is happening here. This spawner is the way to use another futures runtime.

Please correct me if I'm wrong.

@kvsari
Copy link

kvsari commented Nov 19, 2020

I have a quick and dirty fork. I've had to resort to using a newtype, NtExec. I couldn't figure out how to make it a trait bound with E: hyper::rt::Executor. It'll do for now to prove whether it can work or not.

To use you'll have to do something like this;

pub struct WarpSpawn(futext::spawner::Spawner);

impl warp::hyper::rt::Executor<Pin<Box<dyn Future<Output = ()> + Send + 'static>>> for WarpSpawn
{
    fn execute(&self, fut: Pin<Box<dyn Future<Output = ()> + Send + 'static>>) {
        self.0.spawn(async { drop(fut.await) }).detach();
    }
}

The futext is a small lib I'm playing with. It's all smol underneath.

Then later inside main...

let warp_spawn = WarpSpawn{ 0: rt.spawner() };
let warp_exec = warp::NtExec{ 0: Arc::new(warp_spawn) };

Again, this all compiles but it doesn't work for me. I'm using websockets in my project and lo and behold, warp hardcodes tokio. I'd have to figure out a way to thread the passed in executor into the ws module. I don't have the time for this right now unfortunately.

Someone else can have a look and see if at least the pure HTTP stuff works.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

8 participants