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

Please document a pattern equivalent to the old Task::local #15

Closed
joshtriplett opened this issue Dec 8, 2020 · 1 comment
Closed

Comments

@joshtriplett
Copy link

Task::local no longer exists, and LocalExecutor requires some setup in order to use. Please consider providing an example (or a pointer to a crate implementing an appropriate pattern) for how to keep a set of local executors around for running non-Send futures, concurrently with the set of normal executors.

@taiki-e
Copy link
Collaborator

taiki-e commented Apr 22, 2021

The following v0.1 example is

use async_executor::{LocalExecutor, Task};

let local_ex = LocalExecutor::new();

local_ex.run(async {
    let task = Task::local(async { 1 + 2 });
    assert_eq!(task.await, 3);
});

almost equivalent to the following in v1:

use async_executor::LocalExecutor;
use futures_lite::future;

let local_ex = LocalExecutor::new();

future::block_on(local_ex.run(async {
    let task = local_ex.spawn(async { 1 + 2 });
    assert_eq!(task.await, 3);
}));

If you want a similar API to v0.1, you can use a helper something like this:

use async_executor::LocalExecutor;

let local_ex = LocalExecutor::new();

helper::run_local(async {
    let task = helper::spawn_local(async { 1 + 2 });
    assert_eq!(task.await, 3);
});

mod helper {
    use async_executor::{LocalExecutor, Task};
    use scoped_tls::scoped_thread_local;

    scoped_thread_local!(static LOCAL_EX: LocalExecutor);
    
    pub fn run_local<T>(local_ex: &LocalExecutor, future: impl std::future::Future<Output = T>) -> T {
        LOCAL_EX.set(local_ex, || {
            futures_lite::future::block_on(local_ex.run(f))
        })
    }

    pub fn spawn_local<T>(future: impl std::future::Future<Output = T>) -> Task<T> {
        if LOCAL_EX.is_set() {
            LOCAL_EX.with(|local_ex| local_ex.spawn(future))
        } else {
            panic!("`spawn_local()` must be called from a `LocalExecutor`")
        }
    }
}

Note that in 0.1 LocalExecutor::run + Task::local and similar API like above, you can easily write code like can cause a deadlock due to recursive block-on.

refs: a28a964

@taiki-e taiki-e closed this as completed Apr 22, 2021
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

2 participants