Python: многопоточность не улучшает время выполнения - PullRequest
0 голосов
/ 11 мая 2018

Я пытаюсь написать простой многопоточный скрипт на Python:

from multiprocessing.dummy import Pool as ThreadPool

def resize_img_folder_multithreaded(img_fldr_src,img_fldr_dst,max_num_of_thread):

    images = glob.glob(img_fldr_src+'/*.'+img_file_extension)
    pool = ThreadPool(max_num_of_thread) 

    pool.starmap(resize_img,zip(images,itertools.repeat(img_fldr_dst)))
    # close the pool and wait for the work to finish 
    pool.close() 
    pool.join() 


def resize_img(img_path_src,img_fldr_dest):
    #print("about to resize image=",img_path_src)
    image = io.imread(img_path_src)         
    image = transform.resize(image, [300,300])
    io.imsave(os.path.join(img_fldr_dest,os.path.basename(img_path_src)),image)      
    label = img_path_src[:-4] + '.xml'
    if copyLabels is True and os.path.exists(label) is True :
        copyfile(label,os.path.join(img_fldr_dest,os.path.basename(label)))

установка аргумента max_num_of_thread для любого числа в [1 ... 10] не улучшает мое время выполнения привсе (for 60 images it stays around 30 sec), max_num_of_thread = 10 мой компьютер застрял

мой вопрос: что такое горлышко бутылки в моем коде, почему я не вижу никаких улучшений?

некоторые данные о моем ПК:

python -V
Python 3.6.4 :: Anaconda, Inc.


cat /proc/cpuinfo | grep 'processor' | wc -l
4

cat /proc/meminfo 
MemTotal:        8075960 kB
MemFree:         3943796 kB
MemAvailable:    4560308 kB

cat /etc/*release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=17.10

Ответы [ 3 ]

0 голосов
/ 11 мая 2018

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

Заполнение очереди и управление многопроцессорностью в python

0 голосов
/ 11 мая 2018

Проблема возникает из-за Глобальной блокировки интерпретатора или GIL.GIL позволяет запускать только один поток за раз, поэтому, если вы хотите выполнять параллельные вычисления, используйте Processing.Pool :

import multiprocessing

pool = multiprocessing.Pool(max_num_of_process)  # Use number of core as max number

!!! multiprocessing.dummy Является оболочкой для потокового модуля, она позволяет вам взаимодействовать с потоковым пулом так же, как и при использовании обрабатывающего пула.

0 голосов
/ 11 мая 2018

Обвините GIL.

В Python этот механизм называется GIL, глобальной блокировкой интерпретатора.Это в основном мьютекс, который не позволяет нативным потокам одновременно выполнять байт-коды Python.Это должно быть сделано, поскольку управление памятью в Python (по крайней мере, CPython) не является поточно-ориентированным.

Другими словами, GIL не позволит вам запускать несколько потоков одновременно.По сути, вы запускаете один поток за раз.Многопоточность, в смысле эксплуатации нескольких ядер ЦП, больше похожа на иллюзию в Python.

К счастью, есть способ решить эту проблему.хотя это немного дороже с точки зрения ресурсов.Вместо этого вы можете использовать многопроцессорность.Python имеет отличную поддержку для этого через модуль multiprocessing.Таким образом, вы сможете достичь параллелизма [1] .

Вы можете спросить, почему на многопроцессорность не влияют ограничения GIL.Ответ довольно прост.У каждого нового процесса в вашей программе есть свой экземпляр (я думаю, есть более подходящее слово) интерпретатора Python.Это означает, что каждый процесс имеет свой собственный GIL.Таким образом, процессы управляются не GIL, а самой ОС.Это дает вам параллелизм [2] .


Ссылки

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...