Почему больше рабочих, чем процессоров в многопроцессорном Python улучшают время выполнения? - PullRequest
0 голосов
/ 11 июня 2018

Я играю с concurrent.future в python, чтобы понять несколько простых реализаций, использующих многопроцессорность.Однако я столкнулся с очень неожиданным результатом.Прежде чем начать, вот мои системные данные:

Тип компьютера: ноутбук с Windows 10 Оперативная память: 8,00 ГБ Процессор: Intel (R) Core(TM) i7-6600U @ 2.60 ГГц Базовая скорость: 2,80 ГГц Сокеты: 1 Ядра: 2 Логические процессоры: 4 Кэш-память L1:128 КБ кэш L2: 512 КБ кэш L3: 4,0 МБ

    Возьмите следующий геометрический ряд, который вычисляет среднее значение nчисла:

    https://i.stack.imgur.com/Vr0Im.png

    С учетом этой идеи я создаю функцию, которая вычисляет среднее значение целых чисел между нижней границей a (включительно) и верхней границей b (эксклюзив).Затем я запускаю тест с и без многопроцессорной обработки в диапазоне 500 миллионов целых чисел:

    import time
    import concurrent.futures
    
    def mean(a, b):
        total_sum = 0
        for next_int in range(a, b):
            total_sum += next_int
        return total_sum / (b - a)
    
    if __name__ == '__main__':
        n = 500000000              # 500 Million
        wall_time = time.time()
        base_ans = mean(0, n)      # From 0 to n-1.
        print("Single Thread Time: " + str(time.time() - wall_time) + " sec.")
    
        work = [(0, int(n/2)), (int(n/2), n)]
        num_workers = 2            # One process per core!
        test_ans = 0
        wall_time = time.time()
    
        with concurrent.futures.ProcessPoolExecutor(max_workers=num_workers) as executor:
            future_tasks = {executor.submit(mean, job[0], job[1]): job for job in work}
            for future in concurrent.futures.as_completed(future_tasks):
                test_ans += future.result()
    
        print("Multiprocessing Time: " + str(time.time() - wall_time) + " sec.")
        print(str(base_ans) + " == " + str(test_ans / num_workers) + " => " + str(base_ans == (test_ans / num_workers)))
    

    Следующее выдает следующий вывод:

    Single Thread Time: 41.0769419670105 sec.     # CPU Utilization ≈ 35% (from task manager)
    Multiprocessing Time: 24.71605634689331 sec.  # CPU Utilization ≈ 70% (from task manager)
    

    Как мы можем ясно видеть, наблюдалось значительное ускорение ( примерно 1,66x ).Однако, если я создаю 4 рабочих, а не 2, я получаю еще большую скорость:

    work = [(0, int(n/4)), (int(n/4), int(n/2)), (int(n/2), int(3*n/4)), (int(3*n/4), n)]
    num_workers = 4
    # ...
    Single Thread Time: 41.51883292198181 sec.     # CPU Utilization ≈ 35% (from task manager)
    Multiprocessing Time: 18.18532919883728 sec.  # CPU Utilization = 100% (from task manager)
    

    Здесь можно увидеть еще большее увеличение скорости ( примерно 2,28x ) иэто даже состоит из многих пробегов!

    1. Поскольку в этой двух (физической) базовой системе одновременно могут работать только два процесса, является причиной эффективности планировщика Window причиной этого дальнейшего ускорения?
    2. Как я могу выбрать max_worker номер, который обеспечивает самое быстрое время выполнения?Сколько еще процессов я должен добавить после числа физических ядер?
    3. И, наконец, влияет ли добавление большего числа процессов после числа физических ядер на потоки (в многопоточности) в каждом процессе от эффективности работы?
    ...