2026-08-29 22:58:43 +00:00
|
|
|
'''
|
2026-04-10 20:49:16 +00:00
|
|
|
Integration test: spawning tractor actors from an MPI process.
|
|
|
|
|
|
2026-08-29 22:58:43 +00:00
|
|
|
When a parent is launched via ``mpirun``, Open MPI sets
|
|
|
|
|
``OMPI_*`` env vars that bind ``MPI_Init`` to the ``orted``
|
|
|
|
|
daemon. Tractor children inherit those env vars, so if
|
|
|
|
|
``inherit_parent_main=True`` (the default)
|
2026-04-10 20:49:16 +00:00
|
|
|
the child re-executes ``__main__``, re-imports ``mpi4py``, and
|
|
|
|
|
``MPI_Init_thread`` fails because the child was never spawned by
|
|
|
|
|
``orted``::
|
|
|
|
|
|
|
|
|
|
getting local rank failed
|
|
|
|
|
--> Returned value No permission (-17) instead of ORTE_SUCCESS
|
|
|
|
|
|
|
|
|
|
Passing ``inherit_parent_main=False`` and placing RPC functions in a
|
2026-08-29 22:58:43 +00:00
|
|
|
separate importable module (``_child``) avoids the re-import
|
|
|
|
|
entirely.
|
2026-04-10 20:49:16 +00:00
|
|
|
|
|
|
|
|
Usage::
|
|
|
|
|
|
|
|
|
|
mpirun --allow-run-as-root -np 1 python -m \
|
|
|
|
|
examples.integration.mpi4py.inherit_parent_main
|
2026-08-29 22:58:43 +00:00
|
|
|
|
|
|
|
|
'''
|
2026-04-10 20:49:16 +00:00
|
|
|
|
|
|
|
|
from mpi4py import MPI
|
|
|
|
|
|
|
|
|
|
import os
|
|
|
|
|
import trio
|
|
|
|
|
import tractor
|
|
|
|
|
|
|
|
|
|
from ._child import child_fn
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async def main() -> None:
|
2026-08-29 22:58:43 +00:00
|
|
|
'''
|
|
|
|
|
Spawn an MPI-safe child without replaying the parent main.
|
|
|
|
|
|
|
|
|
|
'''
|
|
|
|
|
rank: int = MPI.COMM_WORLD.Get_rank()
|
|
|
|
|
pid: int = os.getpid()
|
|
|
|
|
print(f'[parent] rank={rank} pid={pid}', flush=True)
|
2026-04-10 20:49:16 +00:00
|
|
|
|
2026-07-02 16:35:37 +00:00
|
|
|
an: tractor.ActorNursery
|
2026-04-10 20:49:16 +00:00
|
|
|
async with tractor.open_nursery(start_method='trio') as an:
|
2026-07-02 16:35:37 +00:00
|
|
|
portal: tractor.Portal = await an.start_actor(
|
2026-04-10 20:49:16 +00:00
|
|
|
'mpi-child',
|
|
|
|
|
enable_modules=[child_fn.__module__],
|
|
|
|
|
# Without this the child replays __main__, which
|
|
|
|
|
# re-imports mpi4py and crashes on MPI_Init.
|
|
|
|
|
inherit_parent_main=False,
|
|
|
|
|
)
|
2026-07-02 16:35:37 +00:00
|
|
|
result: str = await portal.run(child_fn)
|
2026-08-29 22:58:43 +00:00
|
|
|
print(f'[parent] got: {result}', flush=True)
|
2026-04-10 20:49:16 +00:00
|
|
|
await portal.cancel_actor()
|
|
|
|
|
|
|
|
|
|
|
2026-08-29 22:58:43 +00:00
|
|
|
if __name__ == '__main__':
|
2026-04-10 20:49:16 +00:00
|
|
|
trio.run(main)
|