параллельное взятие множества случайных выборок python - PullRequest
0 голосов
/ 27 мая 2020

Я пытаюсь несколько раз запустить функцию, которая требует нескольких позиционных аргументов и включает генерацию случайных чисел (для генерации множества выборок распределения). Для MWE, я думаю, это захватывает все:

import numpy as np
import multiprocessing as mup
from functools import partial

def rarr(xsize, ysize, k):
    return np.random.rand(xsize, ysize)
def clever_array(nsamp, xsize=100, ysize=100, ncores=None):
    np.random.seed()
    if ncores is None:
        p = mup.Pool()
    else:
        p = mup.Pool(ncores)
    out = p.map_async( partial(rarr, xsize, ysize), range(nsamp))
    p.close()
    return np.array(out.get())

Обратите внимание, что последний позиционный аргумент для rarr () - всего лишь фиктивная переменная, поскольку я использую map_asyn c (), который требует итеративного . Теперь, если я запускаю %timeit clever_array(500, ncores = 1), я получаю 208 мс, тогда как %timeit clever_array(500, ncores = 5) занимает 149 мс. Так что определенно происходит некоторый параллелизм (ускорение не очень впечатляет для этого MWE, но вполне прилично для моего реального кода).

Однако мне интересно несколько вещей - есть ли еще естественная реализация, отличная от фиктивной переменной для rarr(), переданной как итерация в map_async, чтобы запускать это много раз? Есть ли какой-нибудь очевидный способ передать аргументы xsize и ysize в rarr(), кроме partial()? И есть ли способ обеспечить разные результаты от разных ядер, кроме инициализации каждый раз другого random.seed ()?

Спасибо за любую помощь!

1 Ответ

1 голос
/ 27 мая 2020

Обычно, когда мы используем многопроцессорность, мы ожидаем разных результатов от каждого вызова функции, поэтому нет смысла вызывать одну и ту же функцию много раз. Чтобы гарантировать случайность вывода выборки, лучше всего отделить случайное состояние (начальное число) от самой функции. Лучший подход, рекомендованный numpy официальным do c, - использовать объект np.random.Generator, созданный через np.random.default_rng([seed]). С этим мы можем изменить ваш код на

import numpy as np
import multiprocessing as mup
from functools import partial

def rarr(xsize, ysize, rng):
    return rng.random((xsize, ysize))

def clever_array(nsamp, xsize=100, ysize=100, ncores=None):
    if ncores is None:
        p = mup.Pool()
    else:
        p = mup.Pool(ncores)
    out = p.map_async(partial(rarr, xsize, ysize), map(np.random.default_rng, range(nsamp)))
    p.close()
    return np.array(out.get())
...