Python и выполнение списочных представлений - PullRequest
6 голосов
/ 02 июня 2011

Предположим, у вас есть понимание списка в Python, например

Values = [ f(x) for x in range( 0, 1000 ) ]

с функцией f без побочных эффектов. Таким образом, все записи могут быть вычислены независимо.

Может ли Python повысить производительность понимания этого списка по сравнению с "очевидной" реализацией; например распараллеливанием разделяемой памяти на многоядерных процессорах?

Ответы [ 3 ]

8 голосов
/ 02 июня 2011

В Python 3.2 они добавили concurrent.futures, хорошую библиотеку для одновременного решения проблем.Рассмотрим пример:

import math, time
from concurrent import futures

PRIMES = [112272535095293, 112582705942171, 112272535095293, 115280095190773, 115797848077099, 1099726899285419, 112272535095293, 112582705942171, 112272535095293, 115280095190773, 115797848077099, 1099726899285419]

def is_prime(n):
    if n % 2 == 0:
        return False

    sqrt_n = int(math.floor(math.sqrt(n)))
    for i in range(3, sqrt_n + 1, 2):
        if n % i == 0:
            return False
    return True

def bench(f):
    start = time.time()
    f()
    elapsed = time.time() - start
    print("Completed in {} seconds".format(elapsed))

def concurrent():
    with futures.ProcessPoolExecutor() as executor:
        values = list(executor.map(is_prime, PRIMES))

def listcomp():
    values = [is_prime(x) for x in PRIMES]

Результаты на моем четырехъядерном ядре:

>>> bench(listcomp)
Completed in 14.463825941085815 seconds
>>> bench(concurrent)
Completed in 3.818351984024048 seconds
8 голосов
/ 02 июня 2011

Нет, Python не будет магически распараллеливать это для вас. Фактически, это не может, так как не может доказать независимость записей; это потребовало бы большой проверки / проверки программы, что невозможно сделать правильно в общем случае.

Если вам нужен быстрый грубый многоядерный параллелизм, я рекомендую joblib вместо:

from joblib import delayed, Parallel
values = Parallel(n_jobs=NUM_CPUS)(delayed(f)(x) for x in range(1000))

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

Обратите внимание, что joblib на самом деле не поддерживает параллелизм совместно используемой памяти: он порождает рабочие процессы , а не потоки, поэтому он несет некоторые накладные расходы на передачу данных рабочим и возвращает результаты в главный процесс. 1012 *

0 голосов
/ 02 июня 2011

Попробуйте, если следующее может быть быстрее:

Values = map(f,range(0,1000))

Это функциональная манера кодирования

Другая идея заключается в замене всех вхождений значений в коде на выражение генератора

imap(f,range(0,1000))  # Python < 3

map(f,range(0,1000))  # Python 3
...