Dosu LogoDosu Logo
Ask
Join our Discord
LanceDB's SpacePublic
LanceDB
DocumentsLanceDB's Space
PyO3 Async Runtime Bridge
PyO3 Async Runtime Bridge
Type
Topic
Status
Published
Created
Aug 3, 2026
Updated
Aug 3, 2026
Created by
Dosu Bot
Updated by
Dosu Bot

PyO3 Async Runtime Bridge#

Module: python/src/runtime.rs

LanceDB's Python bindings (PyO3) need a Tokio async runtime to drive Rust futures from Python. Rather than using pyo3_async_runtimes::tokio directly, the codebase provides a custom fork-safe wrapper: LanceRuntime.

The Problem: pyo3_async_runtimes::tokio + fork()#

pyo3_async_runtimes::tokio stores its multi-threaded Tokio runtime in a OnceLock — once initialized it can never be replaced. Tokio's worker threads do not survive fork(), so a child process that inherits the locked runtime will hang permanently on every future_into_py call.

This affects any Python code using multiprocessing with the default fork start method.

The Solution: LanceRuntime#

LanceRuntime is a pyo3_async_runtimes::generic::Runtime implementation backed by an AtomicPtr<runtime::Runtime> instead of a OnceLock. The key components are:

  • RUNTIME: AtomicPtr — stores a raw pointer to the heap-allocated Tokio runtime.
  • get_runtime() — lazily initializes the runtime on first access using a spin-lock idiom with RUNTIME_INSTALLING.
  • atfork_child() — a pthread_atfork child handler that nulls the pointer without dropping the old runtime (dropping would try to join the now-dead threads and hang). The next spawn then creates a fresh runtime in the child.
  • install_atfork() — registers atfork_child with libc::pthread_atfork once. No-ops on Windows.

The Tokio runtime itself is a standard multi-thread runtime with all features enabled, named "lancedb-tokio-worker".

Task-Local Context#

LanceRuntime implements ContextExt using a tokio::task_local! cell to propagate Python TaskLocals across async boundaries.

Public API#

Two functions are the sole interface for the rest of the python/src/ codebase:

FunctionUsage
future_into_py(py, fut)Converts an async Rust future into a Python awaitable. Drop-in for pyo3_async_runtimes::tokio::future_into_py. Used in #[pymethods].
block_on(fut)Blocks the calling thread on a future. Used in sync #[pyfunction]s. Must not be called from within Tokio worker threads.

Usage in the Codebase#

future_into_py is the dominant pattern, wrapping nearly every async operation exposed to Python. It is imported via use crate::runtime::future_into_py and used in connection.rs, table.rs, and query.rs — for example:

  • Connection operations (connect, open_table, create_table, table_names, namespace management, jobs, etc.) all return Python awaitables via future_into_py.
  • Every #[pymethods] block on Connection passes self_.py() plus a closure returning PyResult<T>.

block_on is used sparingly where sync execution is unavoidable:

  • connect_namespace_client and connect_namespace — synchronous #[pyfunction]s that build namespace database connections.

Dependencies#

Relevant entries in python/Cargo.toml:

  • pyo3 = "0.28" with extension-module, abi3-py39
  • pyo3-async-runtimes = "0.28" with attributes, tokio-runtime features
  • tokio = "1.40" with sync, rt-multi-thread
  • libc = "0.2" for pthread_atfork

Architecture Context#

The Python SDK is a native-binding wrapper over rust/lancedb/ compiled via PyO3. All async Rust operations in the core library are driven through this single runtime bridge.

Key Files#

FileRole
python/src/runtime.rsFull runtime implementation
python/src/connection.rsPrimary consumer of future_into_py and block_on
python/Cargo.tomlDependency declarations
Documents
Apache Arrow Type System
Blob Storage
Cross-Platform Build Support
Deadlock Prevention
Debugger-Safe Object Representation
Hybrid Query Builder
Namespace Layer Architecture
Namespace Manifest Management
Null Type Handling in Lance Writer
PyO3 Async Runtime Bridge
SDK and Multi-Language Architecture
Table Listing API
Vector Search Result Ordering
Vendored Dependency Version Skew
Write Path Architecture
Monitoring with OpenTelemetry Metrics