-
Notifications
You must be signed in to change notification settings - Fork 343
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't quite understand. Owned 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Of course, this was more a comment regarding the available tools to write this, not about the thing this example actually builds
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.
100% agreed
I guess what I am thinking is that given that this is not any thread spawning, but specifically the There was a problem hiding this comment. Choose a reason for hiding this commentThe 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? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd say: use There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oops, sorry -- looks like I missed the mark 😅 There was a problem hiding this comment. Choose a reason for hiding this commentThe 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), | ||
} | ||
}); | ||
} |