2

我今天遇到了这个,不知道为什么。我有几个函数链接在一起,作为更大管道的一部分执行一些耗时的操作。我已经将这些包括在这里,尽可能地简化为一个测试示例。问题是当我直接调用一个函数时,我得到了预期的输出(例如,5 个不同的树)。但是,当我使用 apply_async(或应用,没关系)在多处理池中调用相同的函数时,我得到 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

谢谢!克里斯

4

2 回答 2

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)
于 2014-06-05T06:53:50.613 回答
1

我不是 100% 熟悉这些库,但是,在 Linux 上,(IIRC)multiprocessing使用os.fork. 这意味着随机模块(您正在使用)的状态也将被分叉,并且您的每个进程都将生成相同的随机数序列,从而产生一个不那么随机的_get_random_string函数。

如果我是对的,并且您使池小于您想要的树的数量,您应该会看到您得到 N 组相同的树(其中 N 是池的数量)。

我认为理想的解决方案可能是在每个进程中重新植入随机数生成器。它们不太可能同时运行因此您应该得到不同的结果。

于 2014-06-04T05:32:07.667 回答