Skip to content

Commit

Permalink
Add another performance subsection on implicit access to GIL token.
Browse files Browse the repository at this point in the history
  • Loading branch information
adamreichold committed Jul 9, 2023
1 parent ff78b92 commit bedb682
Showing 1 changed file with 40 additions and 0 deletions.
40 changes: 40 additions & 0 deletions guide/src/performance.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,43 @@ fn frobnicate(value: &PyAny) -> PyResult<&PyAny> {
}
}
```

## Access to GIL-bound reference implies access to GIL token

Calling `Python::with_gil` is effectively a no-op when the GIL is already held, but checking that this is the case still has a cost. If an existing GIL token can not be accessed, for example when implementing a pre-existing trait, but a GIL-bound reference is available, this cost can be avoided by exploiting that access to GIL-bound reference gives zero-cost access to a GIL token via `PyAny::py`.

For example, instead of writing

```rust
# #![allow(dead_code)]
# use pyo3::prelude::*;
# use pyo3::types::PyList;

struct Foo(Py<PyList>);

struct FooRef<'a>(&'a PyList);

impl PartialEq<Foo> for FooRef<'_> {
fn eq(&self, other: &Foo) -> bool {
Python::with_gil(|py| self.0.len() == other.0.as_ref(py).len())
}
}
```

use more efficient

```rust
# #![allow(dead_code)]
# use pyo3::prelude::*;
# use pyo3::types::PyList;
# struct Foo(Py<PyList>);
# struct FooRef<'a>(&'a PyList);
#
impl PartialEq<Foo> for FooRef<'_> {
fn eq(&self, other: &Foo) -> bool {
// Access to `&'a PyAny` implies access to `Python<'a>`.
let py = self.0.py();
self.0.len() == other.0.as_ref(py).len()
}
}
```

0 comments on commit bedb682

Please sign in to comment.