为什么ThreadPoolExecutor比for循环慢?

3

代码1

def feedforward(self,d):
    out = []
    for neuron in self.layer:
        out.append(neuron.feedforward(d))
    return np.array(out)

这是我编写的用于执行前馈的原始代码。我想通过使用多线程来提高执行速度,因此编辑了代码以使用concurrent.futures模块中的ThreadPoolExecutor

代码2

def parallel_feedforward(self,func,param):
    return func.feedforward(param)

def feedforward(self,d):
    out = []
    with ThreadPoolExecutor(max_workers = 4) as executor:
        new_d = np.tile(d,(len(self.layer),1))
        for o in executor.map(self.parallel_feedforward,self.layer,new_d):
            out.append(o)
    return np.array(out)

变量d是一个向量,我使用了np.tile()来使executor.map正确接受输入。

在测试两者执行速度后,我发现代码1明显比代码2快得多(代码2慢了近8-10倍)。但是,使用多线程的代码不应该比循环更快吗?这是因为我编写的代码有误还是其他原因导致的。如果是我的代码有问题,请问哪里错了?

提前感谢您的帮助。

1个回答

6

Hari,

你应该快速了解Python和线程-特别是Python "线程"由于Python GIL的存在而无法并行运行(...请在Google上搜索它)。因此,如果您的功能是CPU绑定的,则使用上面的Python线程实际上不会运行得更快。

要真正并行运行,您需要使用ProcessPoolExecutor-这样可以避免线程中存在的python“GIL锁”。


至于为什么它可能会运行8-10倍 - 只是有一个想法,当您使用futures时,当您通过参数向执行程序发出调用时,futures将对您的参数进行pickle以传递给工作人员,然后工作人员将在线程/进程中un-pickle来使用。(如果这对你来说很新,请在Python pickling上快速搜索)

如果您具有非平凡大小的参数,这可能需要大量时间。

所以这可能是您看到减速的原因。...我自己的代码也因为尝试向工人传递大量参数而出现了巨大的减速。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接