Багатопроцесорна обробка циклу for?


81

У мене є масив (що називається data_inputs), що містить імена сотень файлів астрономічних зображень. Потім цими зображеннями маніпулюють. Мій код працює і займає кілька секунд, щоб обробити кожне зображення. Однак він може робити лише одне зображення за раз, оскільки я запускаю масив через forцикл:

for name in data_inputs:
    sci=fits.open(name+'.fits')
    #image is manipulated

Немає жодної причини, чому мені доводиться модифікувати зображення перед будь-яким іншим, так чи можливо використовувати всі 4 ядра на моїй машині, при цьому кожне ядро ​​проходить через цикл for на іншому зображенні?

Я читав про multiprocessingмодуль, але не знаю, як його реалізувати в моєму випадку. Я прагну приступити до multiprocessingроботи, тому що врешті-решт мені доведеться запустити це на 10 000+ зображеннях.

Відповіді:


99

Ви можете просто використовувати multiprocessing.Pool:

from multiprocessing import Pool

def process_image(name):
    sci=fits.open('{}.fits'.format(name))
    <process>

if __name__ == '__main__':
    pool = Pool()                         # Create a multiprocessing Pool
    pool.map(process_image, data_inputs)  # process data_inputs iterable with pool

14
Може бути краще використовувати: pool = Pool(os.cpu_count()) Це більш загальний спосіб використання багатопроцесорної обробки.
Ліор Маген

2
Примітка: os.cpu_count()додано в Python 3.4. Для Python 2.x використовуйте multiprocessing.cpu_count().
dwj

22
Pool()це те саме, щоPool(os.cpu_count())
Тім

18
Детальніше опрацювати коментар @ Tim - Pool()викликається без значення for processes- це те саме, що Pool(processes=cpu_count())незалежно від того, використовуєте ви Python 3 або 2, - тому найкращою практикою в будь-якій версії є використання Pool(). docs.python.org/2/library/multiprocessing.html
Monkpit

7
@LiorMagen, якщо я не помиляюсь, використання пулу (os.cpu_count ()) змусить ОС зависнути до закінчення обробки, оскільки ви не залишаєте в ОС жодних вільних ядер. Для багатьох користувачів пул (os.cpu_count () - 1) може бути кращим вибором
shayelk

24

Ви можете використовувати multiprocessing.Pool:

from multiprocessing import Pool
class Engine(object):
    def __init__(self, parameters):
        self.parameters = parameters
    def __call__(self, filename):
        sci = fits.open(filename + '.fits')
        manipulated = manipulate_image(sci, self.parameters)
        return manipulated

try:
    pool = Pool(8) # on 8 processors
    engine = Engine(my_parameters)
    data_outputs = pool.map(engine, data_inputs)
finally: # To make sure processes are closed in the end, even if errors happen
    pool.close()
    pool.join()

1
Я не можу зрозуміти, що тут таке "data_inputs". Ви цього не визначили. Яке значення я повинен йому надати?
Abhishek dot py

1
Це насправді випливає з відповіді алкоголя, я цитую його коментар (див. Блок коду): "proces data_inputs iterable with pool". Так data_inputsсамо є ітерабельним (як у стандартному map).
ponadto

Документ python лише показує, що можна передати функцію pool.map(func, iterable[, chunksize]). При передачі об’єкта, чи будуть цей об’єкт спільним для всіх процесів? Таким чином, чи можу я записувати всі процеси до одного списку self.list_в об’єкті?
Філіпп

6

Як варіант

with Pool() as pool: 
    pool.map(fits.open, [name + '.fits' for name in datainput])

TypeError: 'Pool' object is not callable
Кріс

Вибачте, моя помилка - це "pool.map", а не просто "pool". Я полагодив це.
Спас
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.