MultiProcessAgentParallelRunner¶
- class pams.runners.MultiProcessAgentParallelRunner(settings, prng=None, logger=None, simulator_class=<class 'pams.simulator.Simulator'>)[source]¶
Multi Process 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 usingconcurrent.futures.ProcessPoolExecutor. Seepams.runners.MultiThreadAgentParallelRunnerfor the details of the parallelization.The start method of
multiprocessingfor the worker processes can be set bysimulation.startMethodin the config, e.g.,"spawn". It must be one ofmultiprocessing.get_all_start_methods()on the platform. If it is not set,default_start_methodis used; if that is None, the default start method of the platform is used.In addition to the internal methods listed in
pams.runners.MultiThreadAgentParallelRunner, subclasses can customize the worker processes by overriding the following members:default_start_method: the start method used whensimulation.startMethodis not set. For example,"spawn"is required for libraries that are not fork-safe, such as PyTorch with CUDA, TensorFlow, and JAX._get_mp_context: the multiprocessing context of the worker processes._receive_synced_attributes_from_worker: sets the attributes listed inpams.agents.Agent.synced_attributeson the agent on the main process.
Note
The agents and the markets are pickled and copied to a worker process for each task. Therefore, only the returned orders, the state of the agent’s pseudo random number generator, and the attributes listed in
pams.agents.Agent.synced_attributesare reflected to the agent on the main process. Other attributes modified inpams.agents.Agent.submit_orders()are discarded, although in-place changes to memory that a library shares between processes, e.g., PyTorch tensors on the CPU, can remain. A warning is issued when an agent assigns or deletes an attribute in its__dict__that is not listed, at most once for each agent class and attribute name per runner. Assigning a str, a number, or a tuple of them equal to the old value is not reported, and changes made in place, e.g., by appending to a list, and changes to attributes in__slots__are not detected. The listed attributes are sent back after every call, even if the agent submits no orders, and are set on the agent before the orders are handled. The listed values and the orders of all the agents of a task are pickled together, so references among them are kept as far as pickling keeps them, e.g., an order that an agent returns and also keeps in a listed attribute is one object on the main process. The objects of the simulation among them, i.e., the simulator, the logger, the fundamentals, the markets, their order books and the orders in the books, the agents, the sessions, the events, the event hooks, the pseudo random number generators of the simulator, the markets, the agents, the sessions, and the events, and the lists, dicts, and sets that these objects except the agents hold as attributes, are sent back as references to the objects on the main process, so the listed values can refer to them. Other objects are copies, including orders that are in no order book when the task is sent, e.g., executed, canceled, or expired orders, which are new copies after every call; such a copy is equal to the order but is not the object that other agents or unlisted attributes refer to. An unlisted attribute that refers to a listed object keeps referring to the old object, so such attributes must be listed too. Other objects shared with other agents, e.g., a model shared by agents, are copied, and which agents share a copy afterwards depends on how the agents are split into tasks."simulator","logger", and"prng", which the runner manages, and"__dict__", which holds all the attributes of the agent, cannot be listed. The names are read on the main process whenever the agent is asked, and a ValueError is raised if they are invalid, both then and in_setup. If the listed values or the orders of an agent cannot be pickled, a RuntimeError that names the agent is raised. See Agents that change their own attributes for an example with PyTorch and other caveats. User-defined agents for this runner can also keep their states through the callbacks such aspams.agents.Agent.submitted_order()andpams.agents.Agent.executed_order(), which are called on the main process, or derive their states from markets.Note
User-defined classes (agents, markets, loggers, etc.) must be picklable. Especially when the start method of multiprocessing is
spawnorforkserver(e.g., macOS and Windows), the definition of user-defined classes must be importable from worker processes, i.e., they should be saved to a module file rather than defined in__main__or in an interactive session.Warning
This class is much slower than
pams.runners.MultiThreadAgentParallelRunnerbecause of the cost of pickling. Agents and markets refer to the simulator, so every task pickles and unpickles the whole simulation: all the agents, all the markets with their histories, the events, and the logger. For example, with 1000pams.agents.FCNAgentagents, the pickled data is about 4 MB, mostly the states of the agents’ pseudo random number generators, and it takes tens of milliseconds to pickle and as long to unpickle. To reduce the cost, the agents asked in parallel are split into at mostnumParallelchunks of consecutive agents, and each chunk is one task. Thus, the simulation is pickled at mostnumParalleltimes per batch instead of once per agent. Large objects held by agents, such as neural network models, are pickled in every task, even in the tasks of other agents, unless they are excluded from pickling, e.g., by__getstate__. Read-only objects of this kind can be loaded once per worker process by the worker initializer (see_get_worker_initializer) instead. The agents should use such an object where the initializer keeps it, e.g., in a module variable, or put it back on themselves in__setstate__; assigning it inpams.agents.Agent.submit_orders()is warned about. These two ways are only for objects that the agents do not change: an object that an agent changes inpams.agents.Agent.submit_orders(), such as a model that it trains, must be listed inpams.agents.Agent.synced_attributes. A listed attribute must be pickled with the agent; if__getstate__drops it, it is deleted from the agent on the main process. The listed attributes are also pickled back after every call of the agent’spams.agents.Agent.submit_orders(). If you want to use parallelization, it is recommended to usepams.runners.MultiThreadAgentParallelRunner.-
default_start_method:
Optional[str] = None¶ start method of the worker processes used when
simulation.startMethodis not set in the config. None means the default start method of the platform. Subclasses can override it, e.g., with"spawn"for libraries that are not fork-safe.- Type:
Optional[str]