py_context_router (erlang_python v2.3.1)

View Source

Scheduler-affinity router for Python contexts.

This module provides automatic routing of Python calls to contexts based on the calling process's scheduler ID. This ensures that processes on the same scheduler reuse the same context, providing good cache locality while still enabling N-way parallelism.

Architecture

   Scheduler 1 ---+
                  +---> Context 1 (Subinterp/Worker)
   Scheduler 2 ---+
                  +---> Context 2 (Subinterp/Worker)
   Scheduler 3 ---+
                  +---> Context 3 (Subinterp/Worker)
   ...            |
   Scheduler N ---+---> Context N (Subinterp/Worker)
   

Usage

   %% Start the router with default settings
   {ok, Contexts} = py_context_router:start(),
  
   %% Get context for current scheduler (automatic routing)
   Ctx = py_context_router:get_context(),
   {ok, Result} = py_context:call(Ctx, math, sqrt, [16], #{}),
  
   %% Or get a specific context by index
   Ctx2 = py_context_router:get_context(2),
  
   %% Bind a specific context to this process
   ok = py_context_router:bind_context(Ctx2),
   Ctx2 = py_context_router:get_context(), %% Returns bound context
  
   %% Unbind to return to scheduler-based routing
   ok = py_context_router:unbind_context().
   

Summary

Functions

Bind a context to the current process for the default pool.

Bind a context to the current process for a specific pool.

Get all context pids from the default pool.

Get all context pids from a pool.

Get the context for the current process from the default pool.

Get a context by index or from a named pool.

Initialize the pool registry.

Check if contexts have been started and are still alive.

List all pool registrations.

Look up which pool a module/function is registered to.

Get the number of contexts in the default pool.

Get the number of contexts in a pool.

Check if a pool has been started and is still alive.

Register a module to use a specific pool for all functions.

Register a specific module/function to use a specific pool.

Start the context router with default settings.

Start the context router with options.

Start a named pool with given size.

Start a named pool with given size and mode.

Stop the context router.

Stop a named pool.

Unbind the current process's context from the default pool.

Unbind the current process's context from a specific pool.

Unregister a module from pool routing.

Unregister a specific module/function from pool routing.

Types

pool_name/0

-type pool_name() :: default | io | atom().

start_opts/0

-type start_opts() :: #{contexts => pos_integer(), mode => py_context:context_mode()}.

Functions

bind_context(Ctx)

-spec bind_context(pid()) -> ok.

Bind a context to the current process for the default pool.

After binding, get_context/0 will always return this context instead of selecting by scheduler.

bind_context(Pool, Ctx)

-spec bind_context(pool_name(), pid()) -> ok.

Bind a context to the current process for a specific pool.

contexts()

-spec contexts() -> [pid()].

Get all context pids from the default pool.

contexts(Pool)

-spec contexts(pool_name()) -> [pid()].

Get all context pids from a pool.

get_context()

-spec get_context() -> pid().

Get the context for the current process from the default pool.

If the process has a bound context, returns that context. Otherwise, selects a context based on the current scheduler ID.

get_context(N)

-spec get_context(pos_integer() | pool_name()) -> pid().

Get a context by index or from a named pool.

When called with an integer, gets the Nth context from the default pool. When called with an atom, gets a scheduler-affinity context from that pool.

init_pool_registry()

-spec init_pool_registry() -> ok.

Initialize the pool registry.

This is called automatically on first registration. Safe to call multiple times - does nothing if already initialized.

is_started()

-spec is_started() -> boolean().

Check if contexts have been started and are still alive.

list_pool_registrations()

-spec list_pool_registrations() -> [{{atom(), atom() | '_'}, pool_name()}].

List all pool registrations.

Returns a list of {{Module, Func}, Pool} tuples.

lookup_pool(Module, Func)

-spec lookup_pool(atom(), atom()) -> pool_name().

Look up which pool a module/function is registered to.

First checks for a specific module+func registration. If not found, checks for a module-only registration. Returns default if no registration found.

num_contexts()

-spec num_contexts() -> non_neg_integer().

Get the number of contexts in the default pool.

num_contexts(Pool)

-spec num_contexts(pool_name()) -> non_neg_integer().

Get the number of contexts in a pool.

pool_started(Pool)

-spec pool_started(pool_name()) -> boolean().

Check if a pool has been started and is still alive.

register_pool(Pool, Module)

-spec register_pool(pool_name(), atom()) -> ok.

Register a module to use a specific pool for all functions.

All calls to Module:* will be routed to the specified pool.

Example:

  %% Route all 'requests' module calls to io pool
  py_context_router:register_pool(io, requests).

register_pool(Pool, Module, Func)

-spec register_pool(pool_name(), atom(), atom()) -> ok.

Register a specific module/function to use a specific pool.

Calls to Module:Func will be routed to the specified pool. More specific registrations (module+func) take precedence over module-only registrations.

Example:

  %% Route requests.get to io pool
  py_context_router:register_pool(io, requests, get).

start()

-spec start() -> {ok, [pid()]} | {error, term()}.

Start the context router with default settings.

Creates one context per scheduler using worker mode.

start(Opts)

-spec start(start_opts()) -> {ok, [pid()]} | {error, term()}.

Start the context router with options.

Options: - contexts - Number of contexts to create (default: number of schedulers) - mode - Context mode: worker, subinterp, or owngil (default: worker)

start_pool(Pool, Size)

-spec start_pool(pool_name(), pos_integer()) -> {ok, [pid()]} | {error, term()}.

Start a named pool with given size.

start_pool(Pool, Size, Mode)

-spec start_pool(pool_name(), pos_integer(), py_context:context_mode()) ->
                    {ok, [pid()]} | {error, term()}.

Start a named pool with given size and mode.

stop()

-spec stop() -> ok.

Stop the context router.

Stops the default pool and removes persistent_term entries.

stop_pool(Pool)

-spec stop_pool(pool_name()) -> ok.

Stop a named pool.

unbind_context()

-spec unbind_context() -> ok.

Unbind the current process's context from the default pool.

After unbinding, get_context/0 will return to scheduler-based selection.

unbind_context(Pool)

-spec unbind_context(pool_name()) -> ok.

Unbind the current process's context from a specific pool.

unregister_pool(Module)

-spec unregister_pool(atom()) -> ok.

Unregister a module from pool routing.

Calls will return to using the default pool.

unregister_pool(Module, Func)

-spec unregister_pool(atom(), atom()) -> ok.

Unregister a specific module/function from pool routing.