Skip to content

Test full parallel MonteCarlo determinism under spawn and forkserver, not only seed derivation #1076

Description

@thc1006

Context

#1054 added test_seed_derivation_is_start_method_invariant, which checks that the per-index seed a worker derives matches the main process under fork, spawn and forkserver. It runs in ordinary CI on all three start methods, which covers the seeding math, but it deliberately exercises only the pure derivation helpers, not a real simulate().

The gap

The end-to-end serial == parallel(n) test still stubs the module-level Flight and skips unless the start method is fork, because the stub reaches workers only through fork inheritance. So the full production path (the real multiprocess pool, __sim_producer, the manager, bound-method pickling, the stochastic object graph, the file writes) is only verified under fork. Python 3.14 made forkserver the POSIX default, and Windows and macOS use spawn, so fork is no longer the default anywhere. The untested modes are the ones most users will actually hit.

A possible direction

Give the worker-invariance test a picklable, top-level flight factory (or a very small real Flight) instead of a module-level monkeypatch, so it can run a short simulate(parallel=True) under spawn and forkserver and assert that serial and parallel produce identical inputs per index, with no gaps or duplicates and an empty error file.

Follow-up to the review discussion on #1054.

Activity

  1. thc1006 commented on Aug 25, 2026

    @thc1006
    ContributorAuthor

    Half of this is covered now, recording which half so the issue stays accurate.

    #1054 adds test_an_index_keeps_its_inputs_when_the_workers_are_spawned, which runs a real simulate() on two and four workers with the start method forced to spawn, and compares the sampled inputs against a serial run of the same seed. No stubbed Flight, and no skip on the start method, so the end-to-end half of this holds for spawn.

    Getting there took fixing the comparison rather than the code. The first version compared serialized records directly and failed, which looked like the guarantee breaking under spawn. It was not: RocketPyEncoder writes signature["hash"] = hash(obj), which is process-local, and a callable source as a dill blob whose bytes differ between processes for a value nothing varies. The test now strips those two fields before comparing.

    Still open: forkserver is exercised only through the derivation helpers, the same as before. Leaving this issue open for that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions