# shiny future sketch session
## participants
name, github, twitter
* Niko Matsakis (nikomatsakis, nikomatsakis)
* Simon Farnsworth (farnz, TrueFarnz)
* Emmanuel Antony (emmanuelantony2000, @emmanuelantony5)
* Zeeshan Ali (zeenix everywhere)
* Jon Gjengset, @jonhoo
* Erich (erichgess on github)
* Sean McArthur (@seanmonstar)
* Alice Ryhl (Darksonn)
## topic
topic: sync/async/blocking
## status quo
[status quo stories](https://rust-lang.github.io/wg-async-foundations/vision/status_quo.html)
* https://rust-lang.github.io/wg-async-foundations/vision/status_quo/alan_finds_database_drops_hard.html
* natural place where sync/async end up interacting
* drop is sync but you're doing it on async things
* https://github.com/rust-lang/wg-async-foundations/pull/167 -- one possible story in this area
* https://github.com/rust-lang/wg-async-foundations/pull/164#issuecomment-824028298
* trait that is designed for sync
* the impl of it wants to be async inside of it
* rustls doesn't have this concept
* https://github.com/rust-lang/wg-async-foundations/blob/master/src/vision/status_quo/barbara_bridges_sync_and_async.md
* problem of trying to do async things inside of an iterator
* https://rust-lang.github.io/wg-async-foundations/vision/status_quo/alan_thinks_he_needs_async_locks.html
* holding sync locks across a yield point can cause deadlocks; other things are in sync code and not interacting with the executor
* if your mutex guard is `Send`, you can get this using sync locks purely in async code
* if you use `spawn_local` to spawn `!Send` tasks, you can have similar problems
* https://rust-lang.github.io/wg-async-foundations/vision/status_quo/barbara_compares_some_cpp_code.html
* core problem: have some function that is normally cheap but (unpredictably) very expensive
*
* Footgun lurking in FuturesUnordered and other concurrency-enabling streams [#2387](https://github.com/rust-lang/futures-rs/issues/2387)
* if you don't poll your futures-unordered regularly, things inside it don't get polled at all
* problem is that we are doing `while let Some(item) = futures_unordered.await` but then inside the loop you do a `await` that means `futures_unordered` is not going to get polled at all
* async C++ developers spawn this into a task; in Rust, this is more painful because of the `'static` bounds and lack of scoped futures and things
## problem: futures-unordered
* sometimes you want to do async things in sync settings
* to address [#2387]--
* could conceivably have scoped tasks to address this
* this would make it easier to fix, but would it help to prevent the code to begin with?
* in sync code, you would have same problem with a tcp listener-- why is it different?
* in async code, it works in small test cases but fails in prod
* somewhat specific to buffering effect
* could you detect it dynamically?
* some kind of tool that is looking for long delays between when it is woken (from the `Waker`) to when it is actually polled
* look for hazards
* jon: did a lot of this in noria ('which things have been woken up but not polled' or 'it took a long time')
* alice: I often show people this little wrapper future you can put around your spawn calls that will help detect what tasks are blocking things
* "when do you spawn things that are long running"
* often runtime dependent
* go trace tool (Erich)
* allows you to trace the flow of communication between threads
* really useful for tracking down small pauses etc; it's slow to run
* https://about.sourcegraph.com/go/an-introduction-to-go-tool-trace-rhys-hiltner/
* go compiler detects common deadlocks and fails compilation, also fatal runtime errors
* existing shiny story: barbara makes a wish
### rough story output
* story goes kind of like this
* you write the buffered code
* you run cargo test
* you get a print-out like "hey this future is being awoken but the task is busy blocking on this other one, you probably want a spawn"
* perhaps it shows up in your IDE
### alternative story
* you write the buffered code
* some lint detects this pattern
## problem: some functions are a bad idea
* lint-- pretty easy to do
* https://rust-lang.github.io/wg-async-foundations/vision/shiny_future/alans_trust_in_the_compiler_is_rewarded.html
* note: sometimes it's ok to use the std/io traits, if you are writing
* could do some dynamic checking as well, part of `cargo test`
* though sometimes that's ok
## problem: some polls are taking too long
* measuring how much time a call to poll takes, look for outliers
* also: which things have been polled but have not returned
## problem: trying to use async code behind a sync interface
* when this actually becomes a problem:
* you are in async code
* the trait or something else forces you
* you need to do an async operation
* what are possible outcomes:
* panic -- today
* how can we expect users to fix it?
* "works" --
* but if thread is blocked
* what are the choices you could do today
* at the async layer, you would do a spawn-blocking around the sync layer
* and sync layer can do a block-on
* but often you don't have access to the async->sync transition point, it's a non-local change
* other option:
* something like block-in-place
* but then the futures that are higher up on the stack are unable to be polled
* similar to the futures-unordered
* one option:
* dynamic wizardry to fork off the sync call (cilk used to do this)
* this pattern would still be a problem:
```rust=
while let Some(x) = futures_unordered.next().await {
spawn_blocking(|| ).await; // <--
}
```
* but if a future *inside* the `futures_unordered` had this issue, and used `spawn_blocking`, that would be ok
```rust=
let mut results = FuturesUnordered::new();
while let Some(x) = futures_unordered.next().await {
results.push(spawn_blocking(|| ...));
}
results.for_each(|_| ()).await;
```
### story one: we do dark magic on the stack and try to make it work automatically
* we dynamically rewrite the stack in some amazing way to make it similar to `spawn_blo`
### story two: we guide user to an edit that works (a)
* you run `cargo test` and you get a helpful print-out
### story three
## assignments
* basic story flows
* cargo test --trace -- figures out bad situations and how to help you (erich)
* magic stack rewriting (seanmonstar/pnkfelix)
* lint for problematic patterns
*