diff --git a/guide/src/async-await.md b/guide/src/async-await.md index 9a517ecf..c14b5d93 100644 --- a/guide/src/async-await.md +++ b/guide/src/async-await.md @@ -30,7 +30,7 @@ Resulting future of an `async fn` decorated by `#[pyfunction]` must be `Send + ' As a consequence, `async fn` parameters and return types must also be `Send + 'static`, so it is not possible to have a signature like `async fn does_not_compile(arg: &PyAny, py: Python<'_>) -> &PyAny`. -However, there is an exception for method receiver, so async methods can accept `&self`/`&mut self`. +However, there is an exception for method receiver, so async methods can accept `&self`/`&mut self`. Note that this means that the class instance is borrowed for as long as the returned future is not completed, even across yield points and while waiting for I/O operations to complete. Hence, other methods cannot obtain exclusive borrows while the future is still being polled. This is the same as how async methods in Rust generally work but it is more problematic for Rust code interfacing with Python code due to pervasive shared mutability. This strongly suggests to prefer shared borrows `&self` to exclusive ones `&mut self` to avoid racy borrow check failures at runtime. ## Implicit GIL holding @@ -91,4 +91,4 @@ To make a Rust future awaitable in Python, PyO3 defines a [`Coroutine`]({{#PYO3_ Each `coroutine.send` call is translated to a `Future::poll` call. If a [`CancelHandle`]({{#PYO3_DOCS_URL}}/pyo3/coroutine/struct.CancelHandle.html) parameter is declared, the exception passed to `coroutine.throw` call is stored in it and can be retrieved with [`CancelHandle::cancelled`]({{#PYO3_DOCS_URL}}/pyo3/coroutine/struct.CancelHandle.html#method.cancelled); otherwise, it cancels the Rust future, and the exception is reraised; -*The type does not yet have a public constructor until the design is finalized.* \ No newline at end of file +*The type does not yet have a public constructor until the design is finalized.*