Найти - Пользователи
Полная версия: От чего зависит количество тредов при использовании ThreadPool из multiprocessing?
Начало » Python для экспертов » От чего зависит количество тредов при использовании ThreadPool из multiprocessing?
1
Master_Sergius
Ковыряю одну багу, соответсвенно, решил на чистом примере потестить этот класс:

import multiprocessing
from multiprocessing.pool import ThreadPool
from time import sleep
 
def do_calculation(data):
        sleep(10)
        return data * 2
 
if __name__ == '__main__':
    pool_size = multiprocessing.cpu_count() * 4
    # pool_size = 2
    print pool_size
    pool = ThreadPool(processes=pool_size)
 
    inputs = list(range(10))
    print 'Input   :', inputs
    pool_outputs = pool.map(do_calculation, inputs)
    print 'Pool    :', pool_outputs

Запускается это дело на линуксах
Количество тредов смотрю вот так:

ps awux -L | grep test_threadpool

На тачках, где 4 и 16 ядер, к размеру pool_size оно добавляет 4 треда, на тачке с 2-мя ядрами, добавляет 3 треда.
В общем, если

print pool_size
показывает 4, то вывод будет примерно таков:

sergius     31269 31269  1.0    8  0.0  65688  3940 pts/3    Sl+  18:07   0:00 python test_threadpool.py
sergius     31269 31270  0.0    8  0.0  65688  3940 pts/3    Sl+  18:07   0:00 python test_threadpool.py
sergius     31269 31271  0.0    8  0.0  65688  3940 pts/3    Sl+  18:07   0:00 python test_threadpool.py
sergius     31269 31272  0.0    8  0.0  65688  3940 pts/3    Sl+  18:07   0:00 python test_threadpool.py
sergius     31269 31273  0.0    8  0.0  65688  3940 pts/3    Sl+  18:07   0:00 python test_threadpool.py
sergius     31269 31274  0.0    8  0.0  65688  3940 pts/3    Sl+  18:07   0:00 python test_threadpool.py
sergius     31269 31275  0.0    8  0.0  65688  3940 pts/3    Sl+  18:07   0:00 python test_threadpool.py
sergius     31269 31276  0.0    8  0.0  65688  3940 pts/3    Sl+  18:07   0:00 python test_threadpool.py

в тестировании принимали участие python 2.6 и 2.7

А поскольку в самом продукте ещё некоторые обертки имеются, то в нем уж количество тредов вообще непонятно с чем коррелируется, к примеру при значении 8 в итоге выходит 32 треда, при значении 2 - 14 тредов. Вот эту загадку мне надо решить. Но для начала надо разобраться как же работает этот ThreadPool
Надеюсь на вашу помощь, господа форумчане.
doza_and
Master_Sergius
Вот эту загадку мне надо решить
Интересно а зачем? В системе живут сотни тредов, одним меньше одни больше какая разница?
Master_Sergius
Ну хотя бы потому, что в продукте вообще не видно какой-то зависимости. Если б там тоже +3 или +4 стабильно на любых значениях - фиг с ним. Я просто ищу всевозможные варианты, где может быть такое расхождение непонятное.

Всё же, некоторая зависимость имеется:

кол-во указанных / кол-во при выводе ps -L
1 / 11
2 / 14
3 / 17
4 / 20
5 / 23
6 / 26
7 / 29
8 / 32

Тобишь, когда +1 добавляем в инициализацию ThreadPool, то на выходе +3. Значит, надо ковырять дальше сам продукт, где ещё завязано…
JOHN_16
я вот бегло глянул код… допустим у вас 4 ядра, пул делаете размером 4*4=16 , а вот задач у вас range(10) то есть 10 … итого на 10 задач 16 процессов, т.е. 6 будут сразу же закрыты за неимением задач…
Master_Sergius
JOHN_16
я вот бегло глянул код… допустим у вас 4 ядра, пул делаете размером 4*4=16 , а вот задач у вас range(10) то есть 10 … итого на 10 задач 16 процессов, т.е. 6 будут сразу же закрыты за неимением задач…

Ну и? Это не объясняет, почему вывод ps показывает 20, а не 16. Там же есть закомментирован кусочек
pool_size = 2
, в результате получаю 6 тредов в выводе ps.
И вот, что самое интересное, если добавить print в функцию, то чётко видно, что выводится именно то количество сообщений, которое равно значению pool_size, потом через 10 секунд то же самое:

def do_calculation(data):
        print "calculating"
        sleep(10)
        return data * 2

И к примеру, pool_size = 2, то тогда в консоли получаем:

calculating
calculating
Через 10 секунд опять 2 сообщения, ну и так далее.
То есть, получается, что оно работает так, как и задумано, только ps показывает лишние треды. Может быть, это какие-то дополнительные осблуживающие, ну или ещё чего? Понимаю, может быть это не столь важно, но наши тестировщики считают это багом, мне нужно раскопать это чемпоглубже.
JOHN_16
Ок. Смотрим на исходный код /usr/lib/python2.7/multiprocessing/pool.py
А именно на инициализатор класса Pool. Видим мы там, что во время выполнения __init__ метода создается 3 внутренних объекта Thread: self._worker_handler, self._task_handler, self._result_handler.
Проверяем практикой - вызываем python, ps сообщает что у нас 1 поток python, создаем пул с pool_size=2, ps сообщает нам о 6 потоках, а именно 1+2+3 (основной поток программы, два созданных нами, 3 внутренних потока объекта Pool).
Создаем Pool с pool_size=16, получаем 20 потоков 1+3+16=20
Т.о. при создании 1 Pool экземпляра будет порождено еще 3 дополнительных потока, можно считать их служебными.

Master_Sergius Думаю вопрос решен?
Master_Sergius
Спасибо, что не поленился, добрый молодец. Я же что-то не подумал посмотреть в Pool, меня сбило с толку то, что в ThreadPool импортируется dummy Process, который подменяет Process для Pool, вот я и смотрел туда, а тут вот оно чё, михалыч. В общем, спасибо, кажется, Я даже догадываюсь где теперь кроется проблема и в самом продукте
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB