pyo3::sync

Struct GILOnceCell

Source
pub struct GILOnceCell<T> { /* private fields */ }
Expand description

A write-once primitive similar to std::sync::OnceLock<T>.

Unlike OnceLock<T> which blocks threads to achieve thread safety, GilOnceCell<T> allows calls to get_or_init and get_or_try_init to race to create an initialized value. (It is still guaranteed that only one thread will ever write to the cell.)

On Python versions that run with the Global Interpreter Lock (GIL), this helps to avoid deadlocks between initialization and the GIL. For an example of such a deadlock, see the FAQ section of the guide.

Note that because the GIL blocks concurrent execution, in practice the means that get_or_init and get_or_try_init may race if the initialization function leads to the GIL being released and a thread context switch. This can happen when importing or calling any Python code, as long as it releases the GIL at some point. On free-threaded Python without any GIL, the race is more likely since there is no GIL to prevent races. In the future, PyO3 may change the semantics of GILOnceCell to behave more like the GIL build in the future.

§Re-entrant initialization

get_or_init and get_or_try_init do not protect against infinite recursion from reentrant initialization.

§Examples

The following example shows how to use GILOnceCell to share a reference to a Python list between threads:

use pyo3::sync::GILOnceCell;
use pyo3::prelude::*;
use pyo3::types::PyList;

static LIST_CELL: GILOnceCell<Py<PyList>> = GILOnceCell::new();

pub fn get_shared_list(py: Python<'_>) -> &Bound<'_, PyList> {
    LIST_CELL
        .get_or_init(py, || PyList::empty(py).unbind())
        .bind(py)
}

Implementations§

Source§

impl<T> GILOnceCell<T>

Source

pub const fn new() -> Self

Create a GILOnceCell which does not yet contain a value.

Source

pub fn get(&self, _py: Python<'_>) -> Option<&T>

Get a reference to the contained value, or None if the cell has not yet been written.

Source

pub fn get_or_init<F>(&self, py: Python<'_>, f: F) -> &T
where F: FnOnce() -> T,

Get a reference to the contained value, initializing it if needed using the provided closure.

See the type-level documentation for detail on re-entrancy and concurrent initialization.

Source

pub fn get_or_try_init<F, E>(&self, py: Python<'_>, f: F) -> Result<&T, E>
where F: FnOnce() -> Result<T, E>,

Like get_or_init, but accepts a fallible initialization function. If it fails, the cell is left uninitialized.

See the type-level documentation for detail on re-entrancy and concurrent initialization.

Source

pub fn get_mut(&mut self) -> Option<&mut T>

Get the contents of the cell mutably. This is only possible if the reference to the cell is unique.

Source

pub fn set(&self, _py: Python<'_>, value: T) -> Result<(), T>

Set the value in the cell.

If the cell has already been written, Err(value) will be returned containing the new value which was not written.

Source

pub fn take(&mut self) -> Option<T>

Takes the value out of the cell, moving it back to an uninitialized state.

Has no effect and returns None if the cell has not yet been written.

Source

pub fn into_inner(self) -> Option<T>

Consumes the cell, returning the wrapped value.

Returns None if the cell has not yet been written.

Source§

impl<T> GILOnceCell<Py<T>>

Source

pub fn clone_ref(&self, py: Python<'_>) -> Self

Creates a new cell that contains a new Python reference to the same contained object.

Returns an uninitialized cell if self has not yet been initialized.

Source§

impl<T> GILOnceCell<Py<T>>
where T: PyTypeCheck,

Source

pub fn import<'py>( &self, py: Python<'py>, module_name: &str, attr_name: &str, ) -> PyResult<&Bound<'py, T>>

Get a reference to the contained Python type, initializing the cell if needed.

This is a shorthand method for get_or_init which imports the type from Python on init.

§Example: Using GILOnceCell to store a class in a static variable.

GILOnceCell can be used to avoid importing a class multiple times:

#[pyfunction]
fn create_ordered_dict<'py>(py: Python<'py>, dict: Bound<'py, PyDict>) -> PyResult<Bound<'py, PyAny>> {
    // Even if this function is called multiple times,
    // the `OrderedDict` class will be imported only once.
    static ORDERED_DICT: GILOnceCell<Py<PyType>> = GILOnceCell::new();
    ORDERED_DICT
        .import(py, "collections", "OrderedDict")?
        .call1((dict,))
}

Trait Implementations§

Source§

impl<T> Default for GILOnceCell<T>

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl<T> Drop for GILOnceCell<T>

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

impl<T: Send> Send for GILOnceCell<T>

Source§

impl<T: Send + Sync> Sync for GILOnceCell<T>

Auto Trait Implementations§

§

impl<T> !Freeze for GILOnceCell<T>

§

impl<T> !RefUnwindSafe for GILOnceCell<T>

§

impl<T> Unpin for GILOnceCell<T>
where T: Unpin,

§

impl<T> UnwindSafe for GILOnceCell<T>
where T: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> Ungil for T
where T: Send,