代码之家  ›  专栏  ›  技术社区  ›  Sun Bear

在concurrent.futures.processpoolexecutor map()和submit()方法中使用numpy.fromiter和numpy.array时出现问题

  •  1
  • Sun Bear  · 技术社区  · 8 年前

    背景 这个 blog 报告的使用速度效益 numpy.fromiter() 结束 numpy.array() 是的。使用提供的脚本作为基础,我希望看到 来自iter的numpy.fromiter() 在执行时 map() 和 submit() python中的方法 concurrent.futures.ProcessPoolExecutor 上课。

    以下是我2秒跑步的结果: array() vs fromiter()

    1. 很明显 来自iter的numpy.fromiter() 比 numpy.array() 当阵列大小通常为<256时。
    2. 然而 来自iter的numpy.fromiter() 和 numpy.array() 当由 MAP() 和 提交() python中的方法 并发.futures.processpoolexecutor 上课。

    问题: 不一致和较差的表现 来自iter的numpy.fromiter() 和 numpy.array() 在使用时 MAP() 和 提交() python中的方法 并发.futures.processpoolexecutor 避免上课?如何改进我的脚本?

    下面给出了我用于此基准测试的python脚本。

    map():

    #!/usr/bin/env python3.5
    import concurrent.futures
    from itertools import chain 
    import time
    import numpy as np
    import pygal
    from os import path
    
    list_sizes = [2**x for x in range(1, 11)]
    seconds = 2
    
    
    def test(size_array):
        pyarray = [float(x) for x in range(size_array)]
    
        start = time.time()
        iterations = 0
        while time.time() - start <= seconds:
            np.fromiter(pyarray, dtype=np.float32, count=size_array)
            iterations += 1
        fromiter_count = iterations
    
        # array
        start = time.time()
        iterations = 0
        while time.time() - start <= seconds:
            np.array(pyarray, dtype=np.float32)
            iterations += 1
        array_count = iterations
    
        #return array_count, fromiter_count
        return size_array, array_count, fromiter_count
    
    
    begin = time.time()
    results = {}
    
    with concurrent.futures.ProcessPoolExecutor(max_workers=6) as executor:
        data = list(chain.from_iterable(executor.map(test, list_sizes)))
        print('data = ', data)
    
    for i in range( 0, len(data), 3 ):
        res = tuple(data[i+1:i+3])
        size_array = data[i]
        results[size_array] = res
        print("Result for size {} in {} seconds: {}".format(size_array,seconds,res))
    
    out_folder = path.dirname(path.realpath(__file__))
    print("Create diagrams in {}".format(out_folder))
    
    chart = pygal.Line()
    chart.title = "Performance in {} seconds".format(seconds)
    chart.x_title = "Array size"
    chart.y_title = "Iterations"
    
    array_result = []
    fromiter_result = []
    x_axis = sorted(results.keys())
    print(x_axis)
    chart.x_labels = x_axis
    chart.add('np.array', [results[x][0] for x in x_axis])
    chart.add('np.fromiter', [results[x][1] for x in x_axis])
    chart.render_to_png(path.join(out_folder, 'result_{}_concurrent_futures_map.png'.format(seconds)))
    
    end = time.time()
    compute_time = end - begin
    print("Program Time = ", compute_time)
    

    提交():

    #!/usr/bin/env python3.5
    import concurrent.futures
    from itertools import chain 
    import time
    import numpy as np
    import pygal
    from os import path
    
    list_sizes = [2**x for x in range(1, 11)]
    seconds = 2
    
    
    def test(size_array):
        pyarray = [float(x) for x in range(size_array)]
    
        start = time.time()
        iterations = 0
        while time.time() - start <= seconds:
            np.fromiter(pyarray, dtype=np.float32, count=size_array)
            iterations += 1
        fromiter_count = iterations
    
        # array
        start = time.time()
        iterations = 0
        while time.time() - start <= seconds:
            np.array(pyarray, dtype=np.float32)
            iterations += 1
        array_count = iterations
    
        return size_array, array_count, fromiter_count
    
    
    begin = time.time()
    results = {}
    
    with concurrent.futures.ProcessPoolExecutor(max_workers=6) as executor:
        future_to_size_array = {executor.submit(test, size_array):size_array
                                for size_array in list_sizes}
        data = list(chain.from_iterable(
            f.result() for f in concurrent.futures.as_completed(future_to_size_array)))
        print('data = ', data)
    
    for i in range( 0, len(data), 3 ):
        res = tuple(data[i+1:i+3])
        size_array = data[i]
        results[size_array] = res
        print("Result for size {} in {} seconds: {}".format(size_array,seconds,res))           
    
    out_folder = path.dirname(path.realpath(__file__))
    print("Create diagrams in {}".format(out_folder))
    
    chart = pygal.Line()
    chart.title = "Performance in {} seconds".format(seconds)
    chart.x_title = "Array size"
    chart.y_title = "Iterations"
    
    x_axis = sorted(results.keys())
    print(x_axis)
    chart.x_labels = x_axis
    chart.add('np.array', [results[x][0] for x in x_axis])
    chart.add('np.fromiter', [results[x][1] for x in x_axis])
    chart.render_to_png(path.join(out_folder, 'result_{}_concurrent_futures_submitv2.png'.format(seconds)))
    
    end = time.time()
    compute_time = end - begin
    print("Program Time = ", compute_time)
    

    序列号:(对 original code )

    #!/usr/bin/env python3.5
    import time
    import numpy as np
    import pygal
    from os import path
    
    list_sizes = [2**x for x in range(1, 11)]
    seconds = 2
    
    
    def test(size_array):
        pyarray = [float(x) for x in range(size_array)]
    
        # fromiter
        start = time.time()
        iterations = 0
        while time.time() - start <= seconds:
            np.fromiter(pyarray, dtype=np.float32, count=size_array)
            iterations += 1
        fromiter_count = iterations
    
        # array
        start = time.time()
        iterations = 0
        while time.time() - start <= seconds:
            np.array(pyarray, dtype=np.float32)
            iterations += 1
        array_count = iterations
    
        return array_count, fromiter_count
    
    
    begin = time.time()
    results = {}
    
    for size_array in list_sizes:
        res = test(size_array)
        results[size_array] = res
        print("Result for size {} in {} seconds: {}".format(size_array,seconds,res))
    
    out_folder = path.dirname(path.realpath(__file__))
    print("Create diagrams in {}".format(out_folder))
    
    chart = pygal.Line()
    chart.title = "Performance in {} seconds".format(seconds)
    chart.x_title = "Array size"
    chart.y_title = "Iterations"
    
    x_axis = sorted(results.keys())
    print(x_axis)
    chart.x_labels = x_axis
    chart.add('np.array', [results[x][0] for x in x_axis])
    chart.add('np.fromiter', [results[x][1] for x in x_axis])
    #chart.add('np.array', [x[0] for x in results.values()])
    #chart.add('np.fromiter', [x[1] for x in results.values()])
    chart.render_to_png(path.join(out_folder, 'result_{}_serial.png'.format(seconds)))
    
    end = time.time()
    compute_time = end - begin
    print("Program Time = ", compute_time)
    
    1 回复  |  直到 8 年前
        1
  •  1
  •   Sun Bear    8 年前

    原因是 numpy.fromiter()和numpy.array()的性能不一致且较差 我之前遇到的似乎是 关联到 这个 concurrent.futures.processpoolexecutor使用的CPU数 是的。我以前用过6个CPU。下图显示了使用2、4、6和8个CPU时numpy.fromiter()和numpy.array()的相应性能。这些图表表明,存在可以使用的最佳数量的CPU。使用过多的CPU(即4个CPU)可能对较小的阵列大小(512个元素)有害。例如,>4 CPU与串行运行相比,可能会导致性能降低(降低1/2倍),甚至导致性能不一致。

    2cpus 4cpus 6cpus 8cpus

    推荐文章