Подтвердить что ты не робот

Python: многоядерная обработка?

Я читал о Python многопроцессорном модуле. Я все еще не думаю, что у меня очень хорошее понимание того, что он может сделать.

Скажем, у меня есть процессор quadcore, и у меня есть список с 1 000 000 целых чисел, и я хочу получить сумму всех целых чисел. Я мог просто сделать:

list_sum = sum(my_list)

Но это только отправляет его в одно ядро.

Возможно ли, используя модуль многопроцессорности, разделить массив вверх и заставить каждое ядро ​​получить сумму его части и вернуть значение, чтобы суммарная сумма могла быть вычислена?

Что-то вроде:

core1_sum = sum(my_list[0:500000])          #goes to core 1
core2_sum = sum(my_list[500001:1000000])    #goes to core 2
all_core_sum = core1_sum + core2_sum        #core 3 does final computation

Любая помощь будет оценена.

4b9b3361

Ответ 1

Да, возможно сделать это суммирование по нескольким процессам, очень нравится делать это с несколькими потоками:

from multiprocessing import Process, Queue

def do_sum(q,l):
    q.put(sum(l))

def main():
    my_list = range(1000000)

    q = Queue()

    p1 = Process(target=do_sum, args=(q,my_list[:500000]))
    p2 = Process(target=do_sum, args=(q,my_list[500000:]))
    p1.start()
    p2.start()
    r1 = q.get()
    r2 = q.get()
    print r1+r2

if __name__=='__main__':
    main()

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

Ответ 2

Добро пожаловать в мир параллельного программирования.

То, что Python может (и не может) делать, зависит от двух вещей.

  • Что может сделать ОС (и не может). Большинство ОС выделяют процессы на ядра. Чтобы использовать 4 ядра, вам необходимо разбить проблему на четыре процесса. Это проще, чем кажется. Иногда.

  • Что могут делать (и не могут) базовые библиотеки C. Если библиотеки C выставляют функции ОС, а ОС предоставляет возможности аппаратного обеспечения, вы прочны.

Разбить проблему на несколько процессов - особенно в GNU/Linux - легко. Разбейте его на многоступенчатый конвейер.

В случае суммирования миллиона чисел подумайте о следующей оболочке script. Предполагая некоторую гипотетическую программу sum.py, которая суммирует либо диапазон чисел, либо список чисел на stdin.

(sum.py 0 500000 и sum.py 50000 1000000) | sum.py

Это будет иметь 3 параллельных процесса. Два делают суммы из большого количества чисел, третье - суммирование двух чисел.

Поскольку оболочки GNU/Linux и ОС уже обрабатывают некоторые части concurrency для вас, вы можете создавать простые (очень, очень простые) программы, которые читают из stdin, записывают в stdout и предназначены для небольших деталей большой работы.

Вы можете попытаться уменьшить накладные расходы, используя subprocess, чтобы построить конвейер вместо выделения задания в оболочку. Однако вы можете обнаружить, что оболочка очень быстро создает конвейеры. (Он был написан непосредственно на C и предоставляет вам прямые вызовы API OS.)

Ответ 3

Конечно, например:

from multiprocessing import Process, Queue

thelist = range(1000*1000)

def f(q, sublist):
    q.put(sum(sublist))

def main():
    start = 0
    chunk = 500*1000
    queue = Queue()
    NP = 0
    subprocesses = []
    while start < len(thelist):
      p = Process(target=f, args=(queue, thelist[start:start+chunk]))
      NP += 1
      print 'delegated %s:%s to subprocess %s' % (start, start+chunk, NP)
      p.start()
      start += chunk
      subprocesses.append(p)
    total = 0
    for i in range(NP):
      total += queue.get()
    print "total is", total, '=', sum(thelist)
    while subprocesses:
      subprocesses.pop().join()

if __name__ == '__main__':
    main()

приводит к:

$ python2.6 mup.py 
delegated 0:500000 to subprocess 1
delegated 500000:1000000 to subprocess 2
total is 499999500000 = 499999500000

обратите внимание, что эта гранулярность слишком хороша, чтобы стоить нереста процессов - общая задача суммирования небольшая (именно поэтому я могу пересчитать сумму в основном как проверку;-), и слишком много данных возвращается назад и (на самом деле подпроцессам не нужно было бы получать копии подписок, на которых они работают, - индексов было бы достаточно). Таким образом, это "игрушечный пример", где многопроцессорность на самом деле не оправдана. В разных архитектурах (используйте пул подпроцессов, которые выполняют несколько задач для выполнения из очереди, сводят к минимуму перемещение данных взад и вперед и т.д. И т.д.), А на менее гранулированных задачах вы действительно можете получить преимущества с точки зрения производительности.