rustasync / runtime

Empowering everyone to build asynchronous software

Home Page:https://docs.rs/runtime

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Design: separate networking from spawning futures

najamelan opened this issue · comments

I have been considering using runtime, but there are some issues with it's design. I wonder how you feel about them. It's common to spawn futures without using networking (TCP/UDP), especially in libraries which might have to spawn futures, but would leave the choice of executor to client code.

I am surprised by how tightly runtime is coupled to romio and networking. I don't really want to bloat library dependencies like this.

Have you considered separating the two concerns?

commented

If you want to use a specific executor, it's possible to write your own Runtime, and use unimplemented! for the methods you're not interested in. The result in the binary should be rather minimal.

If however you still consider this to be ill-fitting for your use case, it might be worth considering using an executor such as juliex directly.

The idea of Runtime is to provide a cohesive story for async Rust, but also providing flexibility and room for experimentation.

I hope this was helpful!

So if I get it right, since network crates are a hard dependencies of runtime, it's not possible to use this for libraries that don't want to bloat dependencies unnecessarily?

I don't think saying runtime has a hard dependency on networking is a fair assessment. The only dependency on romio and juliex are in the runtime-native subcrate, which are exposed as a default, but optional feature. You can disable this feature and opt for the Tokio runtime provided by the runtime-tokio crate, or you can implement your own, lighter-weight runtime backend by disabling all of runtime's features and using the runtime-raw crate.

Ah, thank you for pointing that out. I completely missed the feature in the main toml. I will look into making alternative runtimes then.

Before @asonix pointed out my ignorance last night, I had already done most of the work for an alternative implementation of a runtime, and after considering making custom implementations for runtime I think I might continue the other crate, mainly because:

  • it doesn't require futures to be boxed (which gives us a reference at least to benchmark against)
  • I don't see a convenient way of implementing the Runtime trait for executors on the current thread that require a run method which isn't in the Runtime trait, like LocalPool from futures 0.3

@yoshuawuyts It feels quite unidiomatic to me to use unimplemented in trait methods (turns compile time errors into runtime errors and does away with the concept of traits being contracts), when network and other methods could be provided by different traits that could be implemented for certain runtimes but not for others. When you want to add more and more features in the future, the risk exists as well that more and more unimplemented!() methods criss-cross the codebase, which might be unwieldy to use safely.

All that being said, I could make runtime-juliex, a copy of runtime-native, strip the dependencies and replace the network related method impls with unimplemented!(). Would you merge such a pull request?

commented

@najamelan If you build runtime-juliex I'd love to merge a PR to link to it from the docs! -- but if we merge code into this repo directly that means I'll then be co-responsible for maintaining it, and I don't really want to be on the hook for that, haha. I think you should just go ahead and publish it under your name!

Thinking about it, it wouldn't be very DRY to copy over runtime-native and just strip out the networking deps/functionality. Would a feature flag not be better? I suppose it would mean putting a feature in runtime as well so it can depend on runtime-native with both network and without?

commented

@najamelan I think copying code in this case is the better option.