0

Я определил два правильных способа вычисления средних значений в python.Как вычислить среднее значение одновременно в python?

def avg_regular(values): 
    total = 0 
    for value in values: 
     total += value 
    return total/len(values) 

def avg_concurrent(values): 
    mean = 0 
    num_of_values = len(values) 
    for value in values: 
     #calculate a small portion of the average for each num and add to the total 
     mean += value/num_of_values 
    return mean 

Первая функция представляет собой регулярный способ вычисления средних значений, но я написал вторую, потому что каждый прогон цикла не зависит от предыдущих запусков. Поэтому теоретически среднее значение может вычисляться параллельно.

Однако «параллельный» (без параллельной работы) занимает около 30% больше времени, чем обычный.

Являются ли мои предположения правильными и стоят потери скорости? если да, как я могу сделать вторую функцию второй?

если нет, то где я пошел не так?

+0

Что вы имеете в виду с асинхронным? В python asyncio делает async IO, но это на самом деле вам не поможет. Вы хотите ускорить вычисления? Посмотрите на numpy.Если вы хотите запускать на нескольких ядрах, посмотрите на многопроцессорность (потоки python не могут одновременно запускать код python). Ваша вторая версия делает больше работы (каждый раз, когда разделение и дополнение), поэтому я не думаю, что это очень удивительно, что для этого требуется больше времени. – syntonym

+0

@syntonym Извините, я имею в виду параллельно не async, так как это вроде бы работает в нескольких потоках. Как я могу использовать для этого многопроцессор? – ChrisIkeokwu

+0

Ofc второй медленнее. Гораздо больше дивизий! – sascha

ответ

1

Введенный вами код в основном отличается от (a1+a2+ ... + an)/n и (a1/n + a2/n + ... + an/n). Результат тот же, но во второй версии больше операций (а именно (n-1) больше делений), что замедляет вычисление. Вы утверждали, что во второй версии каждый цикл работает независимо от других. В первом цикле нам нужна следующая информация, чтобы закончить один цикл: total перед запуском и текущим value. Во второй версии нам нужна следующая информация для завершения одного цикла: mean перед запуском, текущие value и num_of_values. Как вы видите во второй версии, мы даже зависим от больших значений!

Но как мы можем разделить работу между ядрами (что является целью многопроцессорности)? Мы могли бы просто дать одному ядру первую половину значений, а вторую - вторую половину, т. Е. ((a1+a2+ ... + a(n//2)) + (a(n//2 +1) + ... + a(n))/n). Да, работа деления на n не разделяется между ядрами, но это одна инструкция, поэтому нам все равно. Также нам нужно добавить левое общее количество и правое общее количество, которое мы не можем разделить, но опять же это всего лишь одна операция.

Так код, который мы хотим запустить:

def my_sum(values): 
    total = 0 
    for value in values: 
     total += value 
    return total 

Там еще проблема с питоном - обычно можно использовать нити, чтобы сделать вычисления, потому что каждый поток будет использовать одно ядро. Но в этом случае нужно позаботиться о том, чтобы ваша программа не работала в условиях гонки, и сам интерпретатор python также должен позаботиться об этом. CPython решил, что это не стоит и в основном работает только в одном потоке за раз. Основным решением является использование нескольких процессов посредством многопроцессорной обработки.

from multiprocessing import Pool 

if __name__ == '__main__': 

    with Pool(5) as p: 
     results = p.map(my_sum, [long_list[0:len(long_list)//2], long_list[len(long_list)//2:])) 

    print(sum(results)/len(long_list)) # add subresults and divide by n 

Но, конечно, несколько процессов не предоставляются бесплатно. Вам нужно разблокировать, скопировать материал и т. Д., Чтобы вы не получили ускорение в 2 раза, как можно было бы ожидать. Также самое большое замедление фактически использует сам python, он не оптимизирован для быстрых численных вычислений. Существуют разные способы, но использование numpy, вероятно, является самым простым. Просто используйте:

import numpy 
print(numpy.mean(long_list)) 

Это, вероятно, намного быстрее, чем версия python. Я не думаю, что numpy использует многопроцессорную внутреннюю обработку, поэтому можно добиться повышения, используя несколько процессов и быструю реализацию (numpy или что-то другое, написанное на C), но обычно numpy достаточно быстро.

+0

Я не уверен, но я думаю, что вы правы, что Numpy обычно не использует многопроцессорность. Тем не менее, я думаю, что он пытается использовать инструкции по вектору/SIMD, где это возможно, и я считаю, что это часть того, откуда происходит улучшение скорости. – Jarak

+0

@Jarak Похоже, что numpy делает некоторые из своих вычислительных материалов через BLAS, поэтому (при использовании оптимизированной версии) он должен использовать векторный, SIMD, параллелизм уровня инструкций и т. Д. Кроме того, можно скомпилировать BLAS с многопоточным, но я не уверен если сумма использует его. Обычно python относительно медленный, потому что он должен делать много вещей (в основном создавая объекты python) и просто используя что-то вроде [numba] (http://numba.pydata.org/) или [cython] (http: // cython.org/) должно дать значительное ускорение – syntonym

Смежные вопросы