Мультитропроцессинг и rpy2 (с ape)

Я столкнулся с этим сегодня и не могу понять, почему. У меня есть несколько связанных между собой функций, которые выполняют некоторые трудоемкие операции как часть большого конвейера. Я включил их здесь, сравнивая с тестовым примером, как мог. Проблема в том, что когда я вызываю функцию напрямую, я получаю ожидаемый результат (например, 5 разных деревьев). Однако, когда я вызываю ту же функцию в пуле многопроцессорной обработки с apply_async (или apply, не имеет значения), я получаю 5 деревьев, но они все одинаковые.

Я задокументировал это в записной книжке IPython, которую можно посмотреть здесь: http://nbviewer.ipython.org/gist/cfriedline/0e275d528ff1a8d674c6

В ячейке 91 я создаю 5 деревьев (каждое с 10 подсказками) и возвращаю два списка. Первый содержит немультипроцессорные деревья, а второй из apply_async.

В ячейке 92 вы можете видеть результаты создания деревьев без многопроцессорной обработки, а в 93 - с многопроцессорной обработкой.

Я ожидаю, что между двумя тестами будет всего 10 разных деревьев, но вместо этого все многопроцессорные деревья идентичны. Имеет мало смысла для меня.

Соответствующие версии вещей:

  • Linux 2.6.18-238.12.1.el5 x86_64 GNU / Linux
  • Python 2.7.6:: Anaconda 1.9.2 (64-разрядная версия)
  • IPython 2.0.0
  • Rpy2 2.3.9

Спасибо! Крис

2 ответа

Я решил это, с точкой в ​​правильном направлении от @mgilson. На самом деле, это была проблема со случайными числами, только не в python - в R (вздох). Состояние R копируется при создании пула, что означает его случайное начальное число. Чтобы исправить, просто немного rpy2, как показано ниже, вызывая функцию R set.seed (с некоторыми специфическими для процесса вещами для хорошей меры):

def create_tree(num_tips, type):
    """
    creates the taxa tree in R
    @param num_tips: number of taxa to create
    @param type: type for naming (e.g., 'taxa')
    @return: a dendropy Tree
    @rtype: dendropy.Tree
    """
    r = rpy2.robjects.r
    set_seed = r('set.seed')
    set_seed(int((time.time()+os.getpid()*1000)))
    rpy2.robjects.globalenv['numtips'] = num_tips
    rpy2.robjects.globalenv['treetype'] = type
    name = _get_random_string(20)
    if type == "T":
        r("%s = rtree(numtips, rooted=T, tip.label=paste(treetype, seq(1:(numtips)), sep=''))" % name)
    else:
        r("%s = rtree(numtips, rooted=F, tip.label=paste(treetype, seq(1:(numtips)), sep=''))" % name)
    tree = r[name]
    return ape_to_dendropy(tree)

Однако я не на 100% знаком с этими библиотеками в Linux (IIRC). multiprocessing использования os.fork, Это означает, что состояние случайного модуля (который вы используете) также будет разветвленным и что каждый из ваших процессов будет генерировать одну и ту же последовательность случайных чисел, что приведет к не столь случайному _get_random_string функция.

Если я прав, и вы сделаете пул меньше, чем количество деревьев, которое вы хотите, вы должны увидеть, что вы получаете группы из N одинаковых деревьев (где N - количество пулов).

Я думаю, что, вероятно, идеальное решение - заново запустить генератор случайных чисел внутри каждого из процессов. Маловероятно, что они будут работать в одно и то же время, поэтому вы должны получить разные результаты.

Другие вопросы по тегам