Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Add a small example on how to integrate threads #21

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

Closed
skade wants to merge 4 commits into master from integrate-threads-example
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions examples/integrate-thread.rs
View file Open in desktop
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#![feature(async_await)]

use async_std::task;

use futures::channel::oneshot;
use std::{thread, time};

struct AsyncHandle<T> {
Copy link
Member

@dignifiedquire dignifiedquire Aug 14, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am struggling with the fact that I have to write my own struct with join logic to make this work :/ This does not feel like an nice easy api surface if I have to write structs to be able to use it.

I might be exaggerating, and this is a lot better than many other async/task apis, but it doesn't feel quite there yet.

Copy link
Collaborator Author

@skade skade Aug 14, 2019
edited
Loading

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't quite understand. std::thread is a foreign api, so I need to write some kind of handle to integrate it. It's an example strategy on how to do such things, not an API proposal.

Owned structs, essentially handles, are quite usual in Rust for this.

JoinHandle in itself is sync and if we don't implement out own threading API, we will have to reach for a bridge.

Yes, this could be provided e.g. by a full thread pool library, but helping users to understand how they can write their own is also important.

Copy link
Member

@dignifiedquire dignifiedquire Aug 14, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's an example strategy on how to do such things, not an API proposal.

Of course, this was more a comment regarding the available tools to write this, not about the thing this example actually builds

Owned structs, essentially handles, are quite usual in Rust for this.

Thinking about it more you are right, I might be just burnt from having to write ETOOMANY Future structs, that I have become very skeptical of apis that require you to do so.

Yes, this could be provided e.g. by a full thread pool library, but helping users to understand how they can write their own is also important.

100% agreed

Yes, this could be provided e.g. by a full thread pool library,

I guess what I am thinking is that given that this is not any thread spawning, but specifically the std lib, it could make sense to have this already provided by async-std, to make sure the two worlds are easy to bridge.

skade reacted with thumbs up emoji
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see your point. I just tried to implement a Future for AsyncTask and it turns out you quickly run into "field projections". @stjepang, I guess the right way there is to write a poll_fn?

Copy link
Contributor

@yoshuawuyts yoshuawuyts Aug 15, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd say: use async-pool for this. The multiple calls to block_on doesn't seem great; instead I'd probably put it all inside an async fn and park the blocking thread handle inside an async-pool closure until it's resolved. It allows bypassing a lot of the manual channel juggling with something much more robust. Not sure it's published yet tho.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm? The multiple calls are just there to illustrate 2 different cases (panic handling and the happy case). Pool doesn't exist. It's also a useful example to explain how you could bind to other primitives.

Copy link
Contributor

@yoshuawuyts yoshuawuyts Aug 15, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops, sorry -- looks like I missed the mark 😅

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Named the thread variables differently and more telling.

handle: thread::JoinHandle<T>,
notifier: oneshot::Receiver<()>,
}

impl<T> AsyncHandle<T> {
fn thread(&self) -> &std::thread::Thread {
self.handle.thread()
}

async fn join(self) -> std::thread::Result<T> {
// ignore results, the join handle will propagate panics
let _ = self.notifier.await;
self.handle.join()
}
}

fn spawn<F, T>(f: F) -> AsyncHandle<T>
where
F: FnOnce() -> T,
F: Send + 'static,
T: Send + 'static,
{
let (sender, receiver) = oneshot::channel::<()>();

let thread_handle = thread::spawn(move || {
let res = f();
sender.send(()).unwrap();
res
});

AsyncHandle {
handle: thread_handle,
notifier: receiver,
}
}

fn main() {
let sleepy_thread = spawn(move || {
thread::sleep(time::Duration::from_millis(1000));
String::from("Finished")
});

task::block_on(async move {
println!("waiting for sleepy thread");
let thread_result = sleepy_thread.join().await;
match thread_result {
Ok(s) => println!("Result: {}", s),
Err(e) => println!("Error: {:?}", e),
}
});

let panicing_thread = spawn(move || {
panic!("aaah!");
String::from("Finished!")
});

task::block_on(async move {
println!("waiting for panicking thread");
let thread_result = panicing_thread.join().await;
match thread_result {
Ok(s) => println!("Result: {}", s),
Err(e) => println!("Error: {:?}", e),
}
});
}

AltStyle によって変換されたページ (->オリジナル) /