2016-02-20 3 views
1

Я перевел C++ renderer на Python. В рендерере C++ используются потоки, каждый из которых отображает часть изображения. Я хочу сделать то же самое в Python. Кажется, однако, что мой многопоточный код занимает много времени по сравнению с моим кодом одной нити версии. Я новичок в многопроцессорной обработке в Python и поэтому задавался вопросом, действительно ли код ниже делает то, что я имею в виду: создание пула потоков, добавление и выполнение некоторых задач и ожидание их завершения?Многопоточность в Python с ThreadPool

Я знаю, что не могу конкурировать с моей версией C++, но я надеялся победить только одну версию Python.

Мульти нить код

from multiprocessing.pool import ThreadPool 

pool = ThreadPool(processes=4) 
pool.map(run_task(...), range(11)) 
pool.close() 
pool.join() 

Одноместный код нить

for i in range(11): 
    Task(...)(i) 

код Task

def run_task(...): 
    task = Task(...) 
    return task.__call__ 

class Task(): 
    def __init__(self, ...): 
     ... 
    def __call__(self, i): 
     ... 

Edit: я тр чтобы использовать from multiprocessing import Pool. Кажется, это блокирует мой терминал Python в Canopy IDE. При запуске файла из командной строки Windows, я получаю:

C:\Users\Matthias\Documents\Courses\Masterproef\pbrt\Tools\Permeability\src>pyth 
on renderer.py 
Exception in thread Thread-2: 
Traceback (most recent call last): 
    File "C:\Users\Matthias\AppData\Local\Enthought\Canopy\App\appdata\canopy-1.5. 
2.2785.win-x86_64\lib\threading.py", line 810, in __bootstrap_inner 
    self.run() 
    File "C:\Users\Matthias\AppData\Local\Enthought\Canopy\App\appdata\canopy-1.5. 
2.2785.win-x86_64\lib\threading.py", line 763, in run 
    self.__target(*self.__args, **self.__kwargs) 
    File "C:\Users\Matthias\AppData\Local\Enthought\Canopy\App\appdata\canopy-1.5. 
2.2785.win-x86_64\lib\multiprocessing\pool.py", line 342, in _handle_tasks 
    put(task) 
PicklingError: Can't pickle <type 'instancemethod'>: attribute lookup __builtin_ 
_.instancemethod failed 

(Вот почему я предпочитаю темы, над процессами в целом Таким образом, проект решения GIL делает на самом деле не чувствую мне.).

ответ

1

Вы должны использовать пул процессов вместо пула потоков (см. Первый пример here).

Многопоточность не должна использоваться для задач, связанных с CPU, из-за GIL CPython.

Может быть, этот короткий пример будет полезно (давайте назовем его example.py):

from multiprocessing import Pool 
import sys 

if __name__ == '__main__': 

    job_list = [xrange(10000000)]*6 

    if 'p' in sys.argv: 
     p = Pool(2) 
     print("Parallel map") 
     print(p.map(sum, job_list)) 
    else: 
     print("Sequential map") 
     print(map(sum, job_list)) 

Моя машина имеет 2 ядра и example.py p (параллельно) версии в два раза быстрее, чем последовательный один. Если мы уменьшим объем выполняемой работы (суммируя десять чисел вместо десяти миллионов), последовательная версия выигрывает из-за ненужных накладных расходов на создание процессов и делегирование задач в параллельной версии.

+0

Я могу запустить небольшой пример. Но для моего полного кода у меня, похоже, проблема с рассолом (какая структура данных? Нет идеи).Каждая задача получает некоторые ссылки на структуры данных (например, полную сцену, которая может быть гигантской), которую все они нуждаются в чтении, а также фильм, который они все обновляют. Так что отключение GIL (если возможно?) Действительно решит все. – Matthias

+1

В этом случае вы можете попытаться запустить свою поточную реализацию с помощью чего-то другого, кроме CPython. Например, у Jython и IronPython нет GIL – mzc

+0

Я хочу переключиться на Visual Studio с помощью IronPython, надеюсь, это выполнит задание – Matthias

1

Нет гарантии, что многопоточный python будет быстрее.

Не говоря уже о накладных расходах на использование потоков (что обычно становится незначительным для «больших» программ), Global Interpreter Lock (GIL) означает, что будет работать только один поток реального чистого Python. В то время как выполняется один поток, остальные должны ждать, пока он опустит GIL (например, во время печати или вызов некоторого кода, отличного от Python).

Поэтому многопоточный Python выгоден, если ваши потоковые задачи содержат блокирующие вызовы, выпускающие GIL, но не гарантированные вообще.

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