首页 > 解决方案 > 使用 python 多处理计算蒙特卡罗模拟中的平均值

问题描述

我一直在阅读有关 Python 中的多处理的内容(例如,我已经阅读过这个这个以及这个这个等等;我还阅读/观看了不同的网站/视频,例如这个这个以及这个等等!)但我是仍然困惑如何将多处理应用于我的特定问题。我编写了一个简单的示例代码,用于使用蒙特卡罗模拟计算随机生成的整数的平均值(我将随机整数存储在一个名为的变量中,以便最终计算平均值;我还生成随机 numpy.ndarrays 并将它们存储在一个名为的变量,因为我需要做一些后处理稍后也在这些数组上):integersarrays

import numpy as np

nMCS = 10 ** 8

integers = []
arrays = []
for i in range(nMCS):
    a = np.random.randint(0,10)
    b = np.random.rand(10,2)

    integers.append(a)
    arrays.append(b)

mean_val = np.average(integers)
# I will do post-processing on 'arrays' later!!

现在我想利用我机器上的所有 16 个内核,所以随机数/数组不是按顺序生成的,我可以加快这个过程。根据我所学,我认识到我需要存储每个蒙特卡罗模拟的结果(即生成的随机整数和随机 numpy.ndarray),然后使用进程间通信以便以后将所有结果存储在一个列表。我编写了不同的代码,但不幸的是它们都不起作用。例如,当我写这样的东西时:

import numpy as np
import multiprocessing

nMCS = 10 ** 6

integers = []
arrays = []

def monte_carlo():
    a = np.random.randint(0,10)
    b = np.random.rand(10,2)

if __name__ == '__main__':
    __spec__ = "ModuleSpec(name='builtins', loader=<class '_frozen_importlib.BuiltinImporter'>)" # this is because I am using Spyder!

    p1 = multiprocessing.Process(target = monte_carlo)

    p1.start()

    p1.join()

    for i in range(nMCS):

        integers.append(a)
        arrays.append(b)

我收到错误“名称'a'未定义”。那么任何人都可以帮我解决这个问题并告诉我如何同时生成尽可能多的随机整数/数组,然后将它们全部添加到列表中以供进一步处理?

标签: pythonmultiprocessing

解决方案


由于返回大量结果会导致进程之间的传播时间,我建议将任务分成几部分并在返回之前对其进行处理。

n = 4
def monte_carlo():
    raw_result = []
    for j in range(10**4 / n):
        a = np.random.randint(0,10)
        b = np.random.rand(10,2)
        raw_result .append([a,b])
    result = processResult(raw_result) 
    #Your method to reduce the result return, 
    #let's assume the return value is [avg(a),reformed_array(b)]
    return result

if __name__ == '__main__':
    __spec__ = "ModuleSpec(name='builtins', loader=<class '_frozen_importlib.BuiltinImporter'>)" # this is because I am using Spyder!

    pool = Pool(processes=4) 
    #you can control how many processes here, for example multiprocessing.cpu_count()-1 to avoid completely blocking

    multiple_results = [pool.apply_async(monte_carlo, (i,)) for i in range(n)]

    data = [res.get() for res in multiple_results]
    #OR
    data = pool.map(monte_carlo, [i for i in range(n)])
    #Both return you a list of [avg(a),reformed_array(b)]

推荐阅读