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

make TokioSpawner completely stateful #18

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

ftelnov
Copy link

@ftelnov ftelnov commented Nov 17, 2023

I propose two things in this PR:

  1. Make tokio spawner completely stateful, so it could take a handle to custom runtime. This is needed, because we don't want the consumers of library to implement the traits themselves. Instead, after this PR, we would be able to simply allow them to use the default implementation. By default tokio spawner would take global runtime. It also fixes tokio's block_on implementation - as it was spawning brand new runtime every call;
  2. Add suffixes to AsyncStd and Tokio spawners(so make them AsyncStdSpawner and TokioSpawner) for easier end-user experience.

This PR breaks backward-compatibilty by adding suffixes to globally-exposed structures and redesigning TokioSpawner.

@ftelnov
Copy link
Author

ftelnov commented Nov 17, 2023

@rmanoka Please, review when you would be able to. From frequent Tokio usage experience, this seems useful

@rmanoka
Copy link
Owner

rmanoka commented Nov 18, 2023

This looks good, but I am worried about the divergence in impl. across tokio and async-std. The runtime is really just a wrapper because tokio_task::block_on consumes a function, not a future.

Can you provide some example use-cases where this is relevant?

@rmanoka rmanoka closed this Nov 18, 2023
@rmanoka rmanoka reopened this Nov 18, 2023
@ftelnov
Copy link
Author

ftelnov commented Nov 18, 2023

I think now AsyncStd and Tokio spawners share the same implementation. Previously, you created runtime in tokio's block_on - even if it is just for wrapping, I guess some work would be done anyway. However, async-std spawner doesn't do such work - it simply uses global executor on every function.

So, to summarize, they are almost the same, the only notable difference atm is that async-std doesn't support custom runtime(because, sadly, it isn't capable enough). What I did in case of block_on is I just removed the creation of new runtime.

@ftelnov
Copy link
Author

ftelnov commented Nov 25, 2023

Hello, @rmanoka, just pinging, knowing that messages without mentions are usually missed. I look forward to answering your questions, or providing additional info if needed!!

@rmanoka
Copy link
Owner

rmanoka commented Nov 28, 2023

Sorry @ftelnov , but I'm not convinced about the use-case of the PR. Currently, I think the impl. is in parity, because internally async's global block_on does something like creating a Task and scheduling it on the local thread. We are doing the same in tokio. Storing the executor that is meant to just run the particular future doesn't seem very useful to me.

@ftelnov
Copy link
Author

ftelnov commented Nov 28, 2023

@rmanoka I think both usages are wrong and divergent at some point of view.
Currently:

  1. async-std spawner just creates the task and delegates its completion to the current globally available runtime. It ensures itself whether it is already created. Runtime is not being erased after block is finished, so block_on basically just uses some global entity to be ran on;
  2. tokio spawner creates the brand new runtime, schedules the future on it, blocks the current thread and then runtime is gone.

You see, they are divergent atm anyway. However, my impl makes them divergent from the different point of view - now tokio spawner assumes that global runtime is available for its methods. Which might be a problem for the end-user.

However, that's the problem of those libraries in the end - they use completely different API and idea. async-std is not really a runtime, it is an async version of the STD. It is just us who use it the same way as tokio.

This usecase is, indeed, very useful for end-users with tokio runtime. Because use cases, where you have multiple tokio runtimes, are normal.

I think, I can lower the divergence between our spawners. Let's bring the same API to the tokio's spawner - in its default implementation, if global runtime is not available yet, we'll create simple one for scheduling, just as you did in block_on. It will both close the gap between runtimes and provide the same semantics for the end-user. What do you think?

@rmanoka
Copy link
Owner

rmanoka commented Nov 29, 2023

async-std uses this line that uses:

pub fn block_on<F: Future<Output = T>, T>(future: F) -> T {
    LOCAL_EXECUTOR.with(|executor| crate::reactor::block_on(executor.run(future)))
}

This seems to be in parity to what we're doing with tokio impl. We could also move to using a thread_local variable in our tokio impl. if it helps anywhere.

@ftelnov
Copy link
Author

ftelnov commented Nov 29, 2023

Yes, it would be similar to what I suggested - we'll create runtime by default(if it is not supplied by user). I'll implement it

@ftelnov
Copy link
Author

ftelnov commented Nov 30, 2023

Hello, @rmanoka ! I've finished.
Currently I use such logic for tokio:

  1. If global runtime is available, we'll block on it;
  2. If global runtime is not available, create ad-hoc local-thread runtime, use it;
  3. When spawner is done, its ad-hoc runtime is being freed.

Following such logic, we close the gap between async-std and tokio. Note that local runtime is kinda last-resort - as tokio was not designed for such things.

It closes the gap between tokio and async-std, bringing similar functionality to tokio.
@ftelnov
Copy link
Author

ftelnov commented Jan 16, 2024

Hello, @rmanoka ! Could you please review the recent update I made on this issue? I look forward to providing you any info you might need!

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

Successfully merging this pull request may close these issues.

2 participants