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