You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Resulting future of an `async fn` decorated by `#[pyfunction]` must be `Send + 'static` to be embedded in a Python object.
29
+
Resulting future of an `async fn` decorated by `#[pyfunction]` must be `Send + 'static` to be embedded in a Python
30
+
object.
30
31
31
-
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<'py>(arg: Bound<'py, PyAny>) -> Bound<'py, PyAny>`.
32
+
As a consequence, `async fn` parameters and return types must also be `Send + 'static`, so it is not possible to have a
33
+
signature like `async fn does_not_compile<'py>(arg: Bound<'py, PyAny>) -> Bound<'py, PyAny>`.
32
34
33
-
However, there is an exception for method receivers, 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` over exclusive ones `&mut self` to avoid racy borrow check failures at runtime.
35
+
However, there is an exception for method receivers, so async methods can accept `&self`/`&mut self`. Note that this
36
+
means that the class instance is borrowed for as long as the returned future is not completed, even across yield points
37
+
and while waiting for I/O operations to complete. Hence, other methods cannot obtain exclusive borrows while the future
38
+
is still being polled. This is the same as how async methods in Rust generally work but it is more problematic for Rust
39
+
code interfacing with Python code due to pervasive shared mutability. This strongly suggests to prefer shared
40
+
borrows `&self` over exclusive ones `&mut self` to avoid racy borrow check failures at runtime.
34
41
35
42
## Implicit GIL holding
36
43
37
-
Even if it is not possible to pass a `py: Python<'py>` parameter to `async fn`, the GIL is still held during the execution of the future – it's also the case for regular `fn` without `Python<'py>`/`Bound<'py, PyAny>` parameter, yet the GIL is held.
44
+
Even if it is not possible to pass a `py: Python<'py>` parameter to `async fn`, the GIL is still held during the
45
+
execution of the future – it's also the case for regular `fn` without `Python<'py>`/`Bound<'py, PyAny>` parameter, yet
46
+
the GIL is held.
38
47
39
-
It is still possible to get a `Python` marker using [`Python::with_gil`]({{#PYO3_DOCS_URL}}/pyo3/marker/struct.Python.html#method.with_gil); because `with_gil` is reentrant and optimized, the cost will be negligible.
48
+
It is still possible to get a `Python` marker
49
+
using [`Python::with_gil`]({{#PYO3_DOCS_URL}}/pyo3/marker/struct.Python.html#method.with_gil); because `with_gil` is
50
+
reentrant and optimized, the cost will be negligible.
40
51
41
52
## Release the GIL across `.await`
42
53
43
-
There is currently no simple way to release the GIL when awaiting a future, *but solutions are currently in development*.
54
+
There is currently no simple way to release the GIL when awaiting a future, *but solutions are currently in
55
+
development*.
44
56
45
57
Here is the advised workaround for now:
46
58
@@ -72,10 +84,12 @@ where
72
84
73
85
## Cancellation
74
86
75
-
Cancellation on the Python side can be caught using [`CancelHandle`]({{#PYO3_DOCS_URL}}/pyo3/coroutine/struct.CancelHandle.html) type, by annotating a function parameter with `#[pyo3(cancel_handle)]`.
87
+
Cancellation on the Python side can be caught
88
+
using [`CancelHandle`]({{#PYO3_DOCS_URL}}/pyo3/coroutine/struct.CancelHandle.html) type, by annotating a function
By default, Python awaitables instantiated with `async fn` can only be awaited in *asyncio* context.
110
+
By default, Python awaitables instantiated with `async fn` can only be awaited in *asyncio* context.
97
111
98
-
PyO3 can also target [*anyio*](https://github.com/agronholm/anyio) with the dedicated `anyio` Cargo feature. With it enabled, `async fn` become awaitable both in *asyncio* or [*trio*](https://github.com/python-trio/trio) context.
112
+
PyO3 can also target [*anyio*](https://github.com/agronholm/anyio) with the dedicated `anyio` Cargo feature. With it
113
+
enabled, `async fn` become awaitable both in *asyncio* or [*trio*](https://github.com/python-trio/trio) context.
99
114
However, it requires to have the [*sniffio*](https://github.com/python-trio/sniffio) (or *anyio*) library installed.
100
115
101
116
## The `Coroutine` type
102
117
103
-
To make a Rust future awaitable in Python, PyO3 defines a [`Coroutine`]({{#PYO3_DOCS_URL}}/pyo3/coroutine/struct.Coroutine.html) type, which implements the Python [coroutine protocol](https://docs.python.org/3/library/collections.abc.html#collections.abc.Coroutine).
118
+
To make a Rust future awaitable in Python, PyO3 defines
119
+
a [`Coroutine`]({{#PYO3_DOCS_URL}}/pyo3/coroutine/struct.Coroutine.html) type, which implements the
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;
122
+
Each `coroutine.send` call is translated to a `Future::poll` call. If
123
+
a [`CancelHandle`]({{#PYO3_DOCS_URL}}/pyo3/coroutine/struct.CancelHandle.html) parameter is declared, the exception
124
+
passed to `coroutine.throw` call is stored in it and can be retrieved
125
+
with [`CancelHandle::cancelled`]({{#PYO3_DOCS_URL}}/pyo3/coroutine/struct.CancelHandle.html#method.cancelled);
126
+
otherwise, it cancels the Rust future, and the exception is reraised;
106
127
107
-
*The type does not yet have a public constructor until the design is finalized.*
0 commit comments