Как использовать инициализатор в Python ThreadPool - PullRequest
4 голосов
/ 25 августа 2011

Я пытаюсь сделать резьбовую свертку, используя PyFFTW, чтобы вычислить большое количество 2D свертки одновременно. (Не нужны отдельные процессы, так как GIL выпущен для Numpy операций). Теперь вот каноническая модель для этого: http://code.activestate.com/recipes/577187-python-thread-pool/

(Py) FFTW очень быстрый, потому что он использует планы. Они должны быть настроены отдельно для каждого потока, чтобы избежать ошибок нарушения прав доступа, например:

class Worker(Thread):
    """Thread executing tasks from a given tasks queue"""
    def __init__(self, tasks):
        Thread.__init__(self)
        self.tasks = tasks
        self.daemon = True

        # Make separate fftw plans for each thread.
        flag_for_fftw='patient'      
        self.inputa = np.zeros(someshape, dtype='float32')
        self.outputa = np.zeros(someshape_semi, dtype='complex64')

        # create a forward plan.
        self.fft = fftw3.Plan(self.inputa,self.outputa, direction='forward', flags=[flag_for_fftw],nthreads=1)         

        # Initialize the arrays for the inverse fft.
        self.inputb = np.zeros(someshape_semi, dtype='complex64')
        self.outputb = np.zeros(someshape, dtype='float32')

        # Create the backward plan.
        self.ifft = fftw3.Plan(self.inputb,self.outputb, direction='backward', flags=[flag_for_fftw],nthreads=1)               
        self.start() 

Таким способом можно передать аргументы self.inputa, self.outputa, self.fft, self.inputb, self.outputb, self.ifft фактическому сверточнику в методе run класса Worker.

Это все хорошо, но мы могли бы также импортировать класс ThreadPool:

from multiprocessing.pool import ThreadPool

Но как мне определить инициализатор в ThreadPool, чтобы получить тот же результат? Согласно документам http://docs.python.org/library/multiprocessing.html msgstr "каждый рабочий процесс будет вызывать инициализатор (* initargs) при запуске". Вы можете легко проверить это в исходном коде Python.

Однако при настройке пула потоков, например, с двумя потоками:

po = ThreadPool(2,initializer=tobedetermined)

и вы запускаете его, возможно, в каком-то цикле

po.apply_async(convolver,(some_input,))

как настроить конволвер инициализатором? Как вы можете сделать это использовать отдельно Планы FFTW в каждом потоке, без пересчета плана FFTW для каждой свертки?

Ура, Алекс.

1 Ответ

1 голос
/ 30 августа 2011

вы можете заключить вызов в конволвер с помощью функции, которая использует локальное хранилище потоков (threading.local()) для инициализации PyFFTW и запоминания результата

...