MultiThreadAgentParallelRunner

class pams.runners.MultiThreadAgentParallelRunner(settings, prng=None, logger=None, simulator_class=<class 'pams.simulator.Simulator'>)[source]

Multi Thread Agent Parallel runner class. This is experimental.

In this runner, only pams.agents.Agent.submit_orders() of normal (non high-frequency) agents is parallelized in each step using concurrent.futures.ThreadPoolExecutor. Order handling, executions, high-frequency agents, events, and logging are processed sequentially on the main thread in the same way as pams.runners.SequentialRunner.

The simulation results are identical to those of pams.runners.SequentialRunner with the same settings and the same seed, because agents are asked to submit orders in the same order and the same number of agents are asked as pams.runners.SequentialRunner does. Agents are asked in batches: at first, maxNormalOrders agents are asked in parallel, and if some of them submit no orders, the same number of the next agents are asked in parallel, and so on, until the number of agents submitting orders reaches maxNormalOrders. This means that the number of agents that can be parallelized is limited by maxNormalOrders of the session.

The number of workers can be set by simulation.numParallel in the config. The default is the number of CPUs minus one (at least one).

Subclasses can customize the workers by overriding the following internal methods:

  • _create_executor: creates the executor.

  • _get_worker_initializer and _get_worker_initargs: a function called once on each worker before it runs any task, and its arguments.

  • _split_agents_into_chunks: splits the agents asked in parallel into the tasks of the executor.

Note

pams.agents.Agent.submit_orders() is called on worker threads concurrently. The built-in agents only read markets and use their own pseudo random number generators, which is thread-safe in this runner because the main thread waits for all the workers before handling orders. User-defined agents must not modify shared objects such as markets, the simulator, the logger, or other agents in pams.agents.Agent.submit_orders(). pams.agents.Agent.submit_orders() is called on the agents themselves, not on copies, so their changes to their own attributes are kept, and pams.agents.Agent.synced_attributes is not used.

Note

Because of the GIL of python, this runner does not speed up CPU-bound agents such as the built-in agents. This runner is beneficial when pams.agents.Agent.submit_orders() waits for I/O (e.g., network access to external models or services).