【问题标题】:Multiprocessing using maximum CPU power in Python-3.x在 Python-3.x 中使用最大 CPU 能力进行多处理
【发布时间】:2014-09-11 16:14:56
【问题描述】:

我正在研究由 32 亿个字符组成的人类基因组,并且我有一个需要在此数据中搜索的对象列表。像这样的:

result_final=[]
objects=['obj1','obj2','obj3',...]

def function(obj):
    result_1=search_in_genome(obj)
    return(result_1)

for item in objects:
    result_2=function(item)
    result_final.append(result_2)

在数据中搜索每个对象需要近 30 秒,而我有几千个对象。我注意到,在串行执行此操作时,仅使用了 7% 的 CPU 和 5% 的 RAM。正如我搜索的那样,为了减少计算时间,我应该使用队列、线程或多处理进行并行计算。但对于非专家来说,它们似乎很复杂。任何人都可以帮助我如何为 python 编写代码以同时运行 10 个搜索,是否可以让 python 使用最大可用 CPU 和 RAM 进行多处理? (我在具有 64Gb RAM、COREI7 和 3.5 GH CPU 的 Windows 7 上使用 Python33)

【问题讨论】:

  • 使用concurrent.futures,特别是concurrent.futures.as_completed,如果您使用的是 Python 2.7,那么 PyPi 中有一个实现。

标签: python multithreading python-3.x queue multiprocessing


【解决方案1】:

您可以为此使用multiprocessing 模块:

from multiprocessing import Pool

objects=['obj1','obj2','obj3',...]

def function(obj):
    result_1=search_in_genome(obj)
    return(result)


if __name__ == "__main__":
    pool = Pool()
    result_final = pool.map(function, objects)

这将允许您跨机器上所有可用的 CPU 扩展工作,因为进程不受 GIL 影响。您不希望运行比可用 CPU 更多的任务。一旦你这样做了,你实际上开始减慢速度,因为 CPU 必须不断在进程之间切换,这会降低性能。

【讨论】:

  • 顺便问一下,这种方法是不是比我这样创建多线程更好,还是只是为了字节码?
  • @katze 由于Global Interpreter Lock (GIL),一次只有一个 Python 线程可以运行 CPU 密集型操作。唯一可以真正并发运行的线程是其中一个正在执行 I/O 操作(从磁盘读取、侦听套接字等)。 OP 正在对内存中的对象进行搜索,每个都意味着没有磁盘 I/O 正在进行,并且搜索受 CPU 限制。这意味着线程不能真正并行化任务。 multiprocessing 模块在进程之间分配工作,因此不受 GIL 影响。
  • @katze 基本上,如果您需要并行化 I/O 密集型工作,线程是一个不错的选择。如果需要并行处理 CPU 密集型工作,则需要使用多个进程。
  • @user3015703 如果您想比较线程与进程的执行方式,您可以将示例的第一行直接更改为:from multiprocessing.pool import ThreadPool as Pool,您将拥有一个线程池而不是进程池。您无需更改任何其他内容。随意尝试两种方式,看看性能如何受到影响。
  • @user3015703 如果您有兴趣了解有关 GIL 如何影响性能的更多信息,我强烈建议您观看this video。它来自一个名为“Understanding the GIL”的 PyCon 演讲,它包含许多非常有用和有趣的信息,关于 GIL 如何影响 CPU 和 I/O 绑定线程的性能,以及影响如何根据线程数和 CPU 的数量而变化正在使用的核心。
【解决方案2】:

好的,我不确定您的问题,但我会这样做(请注意,可能会有更好的解决方案,因为我不是队列对象方面的专家):

如果你想多线程搜索:

class myThread (threading.Thread):

    def __init__(self, obj):

        threading.Thread.__init__(self)

        self.result = None

        self.obj = obj

    #Function who is called when you start your Thread
    def run(self)

        #Execute your function here
        self.result = search_in_genome(self.obj)




if __name__ == '__main__':

    result_final=[]
    objects=['obj1','obj2','obj3',...]

    #List of Thread
    listThread = []

    #Count number of potential thread
    allThread = objects.len()
    allThreadDone = 0

    for item in objects:

        #Create one thread
        thread = myThread(item)

        #Launch that Thread
        thread.start()

        #Stock it into the list
        listThread.append(thread)


    while True:

        for thread in listThread:

            #Count number of Thread who are finished
            if thread.result != None:

                #If a Thread is finished, count it
                allThreadDone += 1

        #If all thread are finished, then stop program
        if allThreadDone == allThread:
            break
        #Else initialyse flag to count again
        else:
            allThreadDone = 0

如果有人可以检查并验证此代码会更好。 (对不起,我的英语顺便说一句)

【讨论】:

  • 在这里如何控制当时正在运行的线程数?!它会检查 CPU 功率以计算可以同时运行的线程数吗?
  • 要知道线程是否正在运行,您可以使用 thread.isAlive() 返回 True 或 False。关于 CPU 功率,我从未在我的程序中使用过它,但也许你可以在这里查看:stackoverflow.com/questions/276052/…
  • 不要为此使用线程。在 Python 中,一次只能有一个线程运行字节码,因此跨线程并行 CPU 密集型任务不会获得任何性能提升。
  • @katze 当我说“字节码”时,我只是指在编译的 Python 代码中执行指令。除非 OP 的程序主要是从磁盘或数据库读取或执行其他一些 I/O 绑定操作,否则它将主要执行字节码。我想我可能误解了 OP 所说的工人在做什么,但我认为他们正在执行 CPU 密集型任务。
  • @katze 您应该使用thread.join() 等待每个线程完成,而不是使用您现在使用的while True: 循环:for thread in listThread: thread.join()
猜你喜欢
  • 2016-10-21
  • 1970-01-01
  • 2020-07-21
  • 2020-12-03
  • 2021-10-17
  • 1970-01-01
  • 2022-08-06
  • 2022-08-24
  • 2021-10-13
相关资源
最近更新 更多