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

How create multiple asynchronous tasks,task have "loop{}" #244

Closed
xiaguangbo opened this issue Mar 19, 2024 · 3 comments
Closed

How create multiple asynchronous tasks,task have "loop{}" #244

xiaguangbo opened this issue Mar 19, 2024 · 3 comments

Comments

@xiaguangbo
Copy link

There are multiple tasks like this that contain "loop{}", using "... after(...). await" prevents asynchronous tasks from blocking the scheduler entirely.
But using "block_on" will block the current thread, I want to create multiple asynchronous tasks in a thread, such as "tokio::task::spawn" to create an asynchronous task, this way of creating will not block the current thread, "esp-rs" is there anything similar

fn main() {
    // It is necessary to call this function once. Otherwise some patches to the runtime
    // implemented by esp-idf-sys might not link properly. See https://github.com/esp-rs/esp-idf-template/issues/71
    esp_idf_svc::sys::link_patches();

    // Bind the log crate to the ESP Logging facilities
    esp_idf_svc::log::EspLogger::initialize_default();

    log::info!("Hello, world!");

    esp_idf_svc::hal::task::block_on(async {
        let mut timer_service = esp_idf_svc::timer::EspTaskTimerService::new()
            .unwrap()
            .timer_async()
            .unwrap();

        loop {
            log::info!("Hello, world!");
            timer_service
                .after(std::time::Duration::from_millis(1000))
                .await
                .unwrap();
        }
    });
}
@Vollbrecht
Copy link
Contributor

rust asynchronous execution always follows a cooperative model. Meaning they never really run in true parallel fashion if they are bound to one thread. You probably first should read about how it works in general, one thing you can do is reading this

If you want to run fully independent async task that you dont want to handle the way described in the link, you can always just spawn a std::thread and create a separate block_on section for it.

While its strictly not needed you can use different async executors that does the job for you here, but it is essentially the same as calling block_on in a certain place. esp-idf-svc is executor agnostic so you can run executors like edge-executor, embassy-executor, smol, tokio just fine. But in the end you probably would also come to the same place where you would spawn different new executors on a different threads.

@xiaguangbo
Copy link
Author

@Vollbrecht
Cargo.toml add tokio = { version = "*", features = ["rt"] }

tokio...block_on is ok.
tokio...spawn is no.
but cargo build no err

fn main() {
    // It is necessary to call this function once. Otherwise some patches to the runtime
    // implemented by esp-idf-sys might not link properly. See https://github.com/esp-rs/esp-idf-template/issues/71
    esp_idf_svc::sys::link_patches();

    // Bind the log crate to the ESP Logging facilities
    esp_idf_svc::log::EspLogger::initialize_default();

    log::info!("Hello, world!");

    tokio::runtime::Builder::new_current_thread()
        .enable_all()
        .build().unwrap()
        .block_on(async {
            log::info!("Hello, world!");
            loop {
            }
        });

tokio::runtime::Builder::new_current_thread()
            .enable_all()
            .build()
            .unwrap()
            .spawn(async {
                log::info!("Hello, world!");

                let mut timer_service = esp_idf_svc::timer::EspTaskTimerService::new()
                    .unwrap()
                    .timer_async()
                    .unwrap();

                loop {
                    log::info!("Hello, world!");
                    timer_service
                        .after(std::time::Duration::from_millis(1000))
                        .await
                        .unwrap();
                }
            });
}

use tokio...spawn in the std::thread::spawn is no

std::thread::spawn(|| {
    tokio...spawn

    loop {
            std::thread::sleep(std::time::Duration::from_secs(1));
        }
});

At present, only block_on can be used. And you can't use tokio::time::sleep, say libc::... err

@xiaguangbo
Copy link
Author

xiaguangbo commented Apr 10, 2024

is ok

fn main() {
    // It is necessary to call this function once. Otherwise some patches to the runtime
    // implemented by esp-idf-sys might not link properly. See https://github.com/esp-rs/esp-idf-template/issues/71
    esp_idf_svc::sys::link_patches();

    // Bind the log crate to the ESP Logging facilities
    esp_idf_svc::log::EspLogger::initialize_default();

    log::info!("Hello, world!");

    // esp_idf_svc::io::vfs::initialize_eventfd(5).unwrap();

    use tokio::time::{sleep, Duration};

    tokio::runtime::Builder::new_current_thread()
        .enable_all()
        .build()
        .unwrap()
        .block_on(async move {
            tokio::spawn(async move {
                loop {
                    log::info!("tokio 2");
                    sleep(Duration::from_millis(1000)).await;
                }
            });

            loop {
                log::info!("tokio 1");
                sleep(Duration::from_millis(1000)).await;
            }
        });
}
[dependencies]
# ...
tokio = { version = "*", features = ["rt", "time"] }

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

No branches or pull requests

2 participants