【问题标题】:python multiprocessing comparisonpython多处理比较
【发布时间】:2022-09-23 19:15:48
【问题描述】:

我正在使用多处理来训练神经网络,其中一个进程构建批处理样本并将它们放入队列中,父进程从队列中读取并使用 pytorch 训练网络。

我注意到使用多进程进行训练的总时间并不比使用单个进程短,并且在进一步调查时,我发现虽然在多进程中从队列中读取比在单个进程中构建队列要快(如预期的那样),多进程中的训练过程(多进程和单进程的代码相同)需要更长的时间。

我编写了一个简单的脚本来举例说明。请参阅下面的脚本:

import multiprocessing as mp
import numpy as np
import time

n = 200

def get_sample():
    local_loop = 400
    # data
    x = np.random.rand(n,n)
    p = np.random.rand(n,n)
    y = 0
    for i in range(local_loop):
        y += np.power(x, p)
    return y

def new_process(q_data, total_loops):
    for i in range(total_loops):
        q_data.put(get_sample())
    print(\'finish new process\')

def main(multi_proc=False):
    st = time.time()
    total_loops = 100
    
    local_loop = 2500
    mt = 0
    other_t = 0

    st_multi = time.time()
    if multi_proc:
        q_data = mp.Queue()
        new_proc = mp.Process(target=new_process,args=(q_data, total_loops))
        new_proc.start()
    mt += time.time() - st_multi

    for i in range(total_loops):
        st_multi = time.time()
        if multi_proc:
            y = q_data.get()
        else:
            y = get_sample()
        mt += time.time() - st_multi

        other_st = time.time()
        for j in range(local_loop):
            y += np.random.rand(n,n)
        other_t += time.time() - other_st

    st_multi = time.time()
    if multi_proc:
        assert q_data.empty()
        new_proc.join()
    mt += time.time() - st_multi

    print(\'\\nmulti_proc\', multi_proc)
    print(\'multi_proc_time\', mt)
    print(\'other_time\', other_t)

    print(f\'total time: {time.time()-st}\')

if __name__ == \'__main__\':
    main(multi_proc=False)
    main(multi_proc=True)

当我运行它时,我得到了结果:

multi_proc False
multi_proc_time 36.44150114059448
other_time 39.08155846595764
total time: 75.5232412815094
finish new process

multi_proc True
multi_proc_time 0.4313678741455078
other_time 40.54900646209717
total time: 40.980711460113525

当 multi_process=True 时other_time 多 1 秒(当它们应该相同时)。这似乎在平台/多个实验中是一致的,在我的真实示例中,它比使用多处理的收益更长,这导致了一个大问题。

任何暗示正在发生什么?

  • 我无法重现这个(使用time.perf_counter() 而不是不准确的time.time()):with mp=False, other_time = 27.13; mp=真,27.173。
  • 无论如何,请记住,您需要为在进程之间传输的每个对象支付(在时间方面)序列化/反序列化“税”。
  • 只是为了证明它确实是热节流,我使用了一台热设计不佳的旧笔记本电脑,并在笔记本电脑以土豆模式工作时(因此没有热问题)两次都在涡轮模式和超线程下工作完全相等,但在 turbo 模式下工作时,多处理代码“其他”的时间要长 2.5 秒。
  • 接得好。我在测试时密切关注我的机器的节流,它保持在 100%。
  • @AKX 你去吧,这个简单的例子在代码的非多处理部分有 5% 的性能差异。如果不是节流,是什么原因?

标签: python multiprocessing


【解决方案1】:

你的结果是我所期望的。但是,您的基准是现实的真实代表吗?

在多处理情况下,您有 3 个进程:

  1. new_process,创建“批量样本”。
  2. 主进程,检索由get_sample 创建的结果。
  3. get_sample 获取由new_process 创建的样本并将结果放入队列以供主进程检索。

    所有 3 个进程都是并行运行的,但上述前两个任务非常简单,与第三个进程相比,需要很少的 CPU 处理。因此,通过并行运行所有三个进程所获得的任何收益都会被将样本和结果从一个地址空间移动到另一个地址空间所需的额外开销所抵消。

    但是,如果创建一个新的批次样本不是那么简单呢?在下面改进的基准测试中,我通过调用 spin_cycles 确保我们在生成新样本时旋转一些 CPU 周期。为了清楚起见,我已经安排了多处理基准和顺序处理基准的代码分开:

    import multiprocessing as mp
    import numpy as np
    import time
    
    n = 200
    total_loops = 20
    local_loops = 400
    
    def spin_cycles():
        # simulate real processing time:
        n = 0
        for i in range(10_000_000):
            n += i * i
        return n
    
    ########### Sequential Benchmark: #######################
    
    def process_sequential(sample):
        # data
        x = np.random.rand(n,n)
        p = np.random.rand(n,n)
        y = 0
        for i in range(local_loops):
            y += np.power(x, p)
        return y
    
    def sequential_processing():
        results = []
        for sample in range(total_loops):
            # simulate real processing time:
            spin_cycles()
            results.append(process_sequential(sample))
    
    def main_sequential():
        st = time.time()
        results = sequential_processing()
        et = time.time()
        print('Sequential time:', et-st)
    
    ########## Multiprocessing Benchmark ################
    
    def process_multi(in_q, out_q):
        for _ in range(total_loops):
            sample = in_q.get()
            # data
            x = np.random.rand(n,n)
            p = np.random.rand(n,n)
            y = 0
            for i in range(local_loops):
                y += np.power(x, p)
            out_q.put(y)
    
    def construct_batch_samples_multi(in_q):
        for sample in range(total_loops):
            # simulate real processing time:
            spin_cycles()
            in_q.put(sample)
    
    def main_multi():
        st = time.time()
        in_q, out_q = mp.Queue(), mp.Queue()
        p1 = mp.Process(target=construct_batch_samples_multi, args=(in_q,))
        p2 = mp.Process(target=process_multi, args=(in_q, out_q))
        p1.start()
        p2.start()
        results = [out_q.get() for _ in range(total_loops)]
        et = time.time()
        p1.join()
        p2.join()
        print('Multiprocessing time:', et-st)
    
    ########### Run Benchmarks #######################
    if __name__ == '__main__':
        main_multi()
        main_sequential()
    

    印刷:

    Multiprocessing time: 19.151983499526978
    Sequential time: 28.005003929138184
    

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-13
    • 2021-09-15
    • 2014-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-08
    相关资源
    最近更新 更多