How to Parallelise TrialsΒΆ
It is possible to repeat a simulation in parallel using the cores available on a given computer. This can lead to decreases in computational time as instead of running each successive simulation one after the other they can be run at the same time.
As an example consider the following simulation network:
>>> import ciw
>>> N = ciw.create_network(
... arrival_distributions=[ciw.dists.Exponential(rate=0.2)],
... service_distributions=[ciw.dists.Exponential(rate=0.1)],
... number_of_servers=[3]
... )
The following function will return the mean wait time:
>>> def get_mean_wait(network, seed=0, max_time=10000):
... """Return the mean waiting time for a given network"""
... ciw.seed(seed)
... Q = ciw.Simulation(network)
... Q.simulate_until_max_time(max_simulation_time=max_time)
... recs = Q.get_all_records()
... waits = [r.waiting_time for r in recs]
... mean_wait = sum(waits) / len(waits)
... return mean_wait
>>> get_mean_wait(network=N)
3.386690...
To be able to better approximate the average wait, the above function will be repeated and the average taken:
>>> max_time = 500
>>> repetitions = 200
>>> mean_waits = [get_mean_wait(network=N, max_time=max_time, seed=seed) for seed in range(repetitions)]
>>> sum(mean_waits) / repetitions
3.762233...
To obtain the above by running 2 simulations at the same time (assuming that 2
cores are available), the multiprocessing
library can be used. In which
case the following main.py
script gives a working
example:
import ciw
import multiprocessing
N = ciw.create_network(
arrival_distributions=[ciw.dists.Exponential(rate=0.2)],
service_distributions=[ciw.dists.Exponential(rate=0.1)],
number_of_servers=[3],
)
max_time = 500
repetitions = 200
def get_mean_wait(network, seed=0, max_time=10000):
"""Return the mean waiting time for a given network"""
ciw.seed(seed)
Q = ciw.Simulation(network)
Q.simulate_until_max_time(max_simulation_time=max_time)
recs = Q.get_all_records()
waits = [r.waiting_time for r in recs]
mean_wait = sum(waits) / len(waits)
return mean_wait
if __name__ == "__main__":
pool = multiprocessing.Pool(processes=2)
args = [(N, seed, max_time) for seed in range(repetitions)]
waits = pool.starmap(get_mean_wait, args)
print(sum(waits) / repetitions)
It is possible to use multiprocessing.cpu_count()
to obtain the number
of available cores.
Note that the conditional if __name__ == '__main__':
is needed to ensure
that get_mean_wait
can be pickled. This is necessary to ensure that it
can be used by the parallel processing pool.
The multiprocessing
library is part of the Python standard library so no
further dependencies are required. However other options are available, one
example of which is dask.