# Warn use of synchronous functions in async code

**URL:** <https://internals.rust-lang.org/t/warn-use-of-synchronous-functions-in-async-code/15515>\
**Category:** tools and infrastructure\
**Created:** [October 26, 2021, 5:56pm UTC](https://internals.rust-lang.org/t/warn-use-of-synchronous-functions-in-async-code/15515 "2021-10-26T17:56:22Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![tvallotton](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tvallotton/32/8153_2.png) [@tvallotton](https://internals.rust-lang.org/u/tvallotton)\
**Post date:** [October 26, 2021, 5:56pm UTC](https://internals.rust-lang.org/t/warn-use-of-synchronous-functions-in-async-code/15515/1 "2021-10-26T17:56:23Z")

</div>

I don't know how we could go about doing something like this, but it would be nice if there was a lint for blocking functions in async code. Occasionally I forget I'm an async function and I do blocking calls. I imagine that in single threaded aplications something like this could be really useful. Has it ever happened to you?

---

<div class="post-metadata">

**Author:** ![toc](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/toc/32/6692_2.png) [@toc](https://internals.rust-lang.org/u/toc)\
**Post date:** [October 26, 2021, 6:03pm UTC](https://internals.rust-lang.org/t/warn-use-of-synchronous-functions-in-async-code/15515/2 "2021-10-26T18:03:37Z")

</div>

Seems like there's some traction.

> <https://github.com/rust-lang/wg-async-foundations/issues/19>
>
> In order to write reliable and performant async code today, the user needs to be… aware of which functions are blocking, and either:
> 
> \- Find an async alternative
> \- Schedule the blocking operation on a separate thread pool (supported by some executors)
> 
> Determining if a function may block is non-trivial: there are no compiler errors, warnings or lints, and blocking functions are not isolated to special crates but rather unpredictably interspersed with non-blocking, async-safe synchronous code. As an example, most of \`std\` can be used in async code, but much of \`std::fs\` and \`std::net\` cannot. To make matters worse, this failure mode is notoriously hard to detect: it often compiles and runs fine when the executor is under a small load (such as in unit tests), but can cause severe application-wide bottlenecks when load is increased (such as in production).
> 
> For the time being, we tell our users that if a sync function uses IO, IPC, timers or synchronization it may block, but such advice adds mental overhead and is prone to human error. I believe it's feasible to find an automated solution to this problem, and that such a solution delivers tangible value.
> 
> \## Proposed goal
> 
> \- Offer a way to declare that a piece of code is blocking.
> \- Detect accidental use of blocking functions in async contexts.
> \- Display actionable advice for how to mitigate the problem.
> \- Offer an override so that users and library authors who "know what they're doing" can suppress detection.
> 
> \## Possible solutions
> 
> I am not qualified to say, and I would like your thoughts! A couple of possibilities:
> 
> \- A new annotation, perhaps \`#\[may\_block\]\` that can be applied on a per-function level.
> \- An auto-trait or other type system integration (although this would be much more invasive).
> 
> \## Challenge 1: Blocking is an ambiguous term
> 
> Typically, blocking is either the result of a blocking syscall or an expensive compute operation. This leaves some ambiguous cases:
> 
> \- Expensive compute is a gray area. Factoring prime numbers is probably blocking, but where's the line exactly? Fortunately, very few (if any) functions in \`std\` involve expensive computation by any reasonable definition.
> \- A method like \`std::sync::Mutex::lock\` is blocking only under certain circumstances. The \`must\_not\_await\` lint is aimed at preventing those circumstances (instead of discouraging its use altogether).
> \- \`TcpStream::write\` blocks by default, but can be overridden to not block using \`TcpStream::set\_nonblocking\`.
> \- The \`println!\` and \`eprintln!\` macros may technically block. Since they lack async-equivalents and rarely block in practice, they are widely used and relatively harmless.
> \- Work-stealing executors may have a higher (but not an infinite) tolerance for sporadic blocking work.
> 
> Ambiguity aside, there are many clear-cut cases (e.g. \`std::thread::sleep\`, \`std::fs::File::write\` and so on) which can benefit from a path forward without the need for bike-shedding.
> 
> \## Challenge 2: Transitivity
> 
> If \`fn foo() { bar() }\` and \`bar()\` is blocking, \`foo()\` is also blocking. In other words, blocking is transitive. If we can apply the annotation transitively, more cases can be detected. OTOH, this can be punted for later.
> 
> \## Challenge 3: Traits
> 
> When dynamic dispatch is used, the concrete method is erased. Should annotations be applied to trait method declaration or in the implementation?
> 
> \## Challenge 4: What is an "async context"?
> 
> The detection should only apply in "async contexts". Does the compiler already have a strict definition for that? Examples from the top of my head:
> 
> \- Directly in an async block or function.
> \- Indirectly in an async block or function, e.g. in a closure.
> \- Inside the \`poll\` method of a custom future impl, or the \`poll\_fn\` macro.
> 
> \## Background reading
> 
> \- \[Comment in the must\_not\_await issue\](https://github.com/rust-lang/wg-async-foundations/pull/16#issuecomment-661457872).
> \- \[Thread on rust-internals\](https://internals.rust-lang.org/t/warning-when-calling-a-blocking-function-in-an-async-context/11440).

> <https://github.com/rust-lang/rust-clippy/issues/4377>
>
> \<!--
> Hi there! Whether you've come to make a suggestion for a new lint, an impr…ovement to an existing lint or to report a bug or a false positive in Clippy, you've come to the right place.
> 
> For bug reports and false positives, please include the output of \`cargo clippy -V\` in the report.
> 
> Thank you for using Clippy!
> 
> Write your comment below this line: --\>
> 
> With \`async/await\` coming up, we will probably see an uptake of such code:
> 
> \`\`\`
> async hello() {
> println!("hello").
> }
> \`\`\`
> 
> Users will most likely not be aware that the call to \`println\` are \_blocking\_. The same goes to any use of the stdlib io apis, most famously \`to\_socket\_addr()\` calls.
> 
> I think there is a chance for clippy to at least find obvious cases of this, for a list of known functions.

---

<div class="post-metadata">

**Author:** ![tvallotton](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tvallotton/32/8153_2.png) [@tvallotton](https://internals.rust-lang.org/u/tvallotton)\
**Post date:** [October 26, 2021, 6:07pm UTC](https://internals.rust-lang.org/t/warn-use-of-synchronous-functions-in-async-code/15515/3 "2021-10-26T18:07:48Z")

</div>

Oh that's nice.

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [January 24, 2022, 6:08pm UTC](https://internals.rust-lang.org/t/warn-use-of-synchronous-functions-in-async-code/15515/4 "2022-01-24T18:08:45Z")

</div>

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
