Форум сайта python.su
0
Всем привет.
У меня возник насущный вопрос о кол-во одновременно работающих потоков. Я понимаю (может и не полностью) что такое GIL, и то, что 100, 200, 1000 потоков в питоне не будут работать нормально и просто зависнут.
Ко мне часто обращаются люди с просьбой написать всякие сканеры портов, которые смогут работать “ОЧЕНЬ БЫСТРО”, и на мой вопрос “насколько быстро” отвечают “ну, потоков в 500-1000”. Я говорю, что это невозможно, а они приводят мне какие-то доводы о том, что какой-то другой автор смог такое сделать. Я конечно же, сразу думаю, что человека обманули, т.к. скорее всего там нет параллельной работы сразу всех потоков, а стоит некий пул, из которого эти потоки по очереди запускаются.
Так вот, я хотел бы уточнить как оно на самом деле бывает, и если все-таки там пул, то где можно посмотреть вразумительный пример на эту тему.
И ещё такой вопрос:
будет ли лучше сделать асинхронный однопоточный сканер, вместо многопоточного?
Всем плюсую, даже за ответы вида “ты что, дурак?” =)
Отредактировано Galvanize (Март 15, 2014 15:09:34)
Офлайн
75
ты что, дурак?
Офлайн
0
Нужен просто оптимальный способ запускать 500 потоков, даже если они не будут работать параллельно и все вместе. Простой пример пула, если возможно, приведите.
Офлайн
857
threading не даёт скорости, просто изображает параллельную работу
для скорости используют multiprocessing
python.org. multiprocessing
python.org. примеры
Galvanizeвсё можно посмотреть в исходниках
и если все-таки там пул, то где можно посмотреть вразумительный пример на эту тему
Отредактировано py.user.next (Март 15, 2014 19:19:17)
Офлайн
253
py.user.nextЭто настоящие потоки. Просто питоновский код слишком часто синхронизируется. Если вы будете запускать из питона долго работающие скомпилированные модули то получите значительное ускорение от применения threading. multiprocessing от threading отличается организацией доступа к общим данным. Другое дело что 1000 потоков не имеют смысла. У вас на машине сколько ядер? ну 8 может 16. Грубо говоря надо 8 потоков или процессов, а остальное все за счет asincio http://docs.python.org/3.4/library/asyncio.html.
threading не даёт скорости, просто изображает параллельную работу
Отредактировано doza_and (Март 16, 2014 06:18:20)
Офлайн
221
Galvanizeне правда. Сам запускал более 100 потоков (из академических целей). Да и в крайнем случае это уже вопрос не к Питону а к ОС.
не будут работать нормально и просто зависнут.
Galvanizeвы не правы. У вас абсолютно нету тонкого понимания особенностей работы потоков и процессов. Тут уже говорили, но я по другому кратко изложу - потоки и процессы распараллеливают код, потоки удобны коммуникацией межу основным потоком и дочерними, но они не приспособлены к нагруженным действиям. Процессы это изолированный код , поэтому на них не распространяется GIL и как следствие они способны “держать” нагрузку.
Ко мне часто обращаются люди с просьбой написать всякие сканеры портов, которые смогут работать “ОЧЕНЬ БЫСТРО”, и на мой вопрос “насколько быстро” отвечают “ну, потоков в 500-1000”. Я говорю, что это невозможно, а они приводят мне какие-то доводы о том, что какой-то другой автор смог такое сделать. Я конечно же, сразу думаю, что человека обманули, т.к. скорее всего там нет параллельной работы сразу всех потоков, а стоит некий пул, из которого эти потоки по очереди запускаются.
Офлайн
0
JOHN_16Ну да, я тоже запускал. Но программа с большим кол-вом потоков не всегда завершается. Данные все собраны, но программа висит. Предполагаю, что они как-то блокируются во время работы и не завершаются. Возможно, что это из-за записи в файл, и блокировок на неё (RLock()).
не правда. Сам запускал более 100 потоков (из академических целей). Да и в крайнем случае это уже вопрос не к Питону а к ОС.
JOHN_16Тонкого понимания, разумеется, у меня нет. Я бы сюда не писал. О том, что потоки и процессы это способ распараллеливания это понятно, и то что процессы не подвержены gil я тоже знал. Но процессов должно быть по 2 на каждое ядро для комфортной работы, а это не совсем быстро.
вы не правы. У вас абсолютно нету тонкого понимания особенностей работы потоков и процессов. Тут уже говорили, но я по другому кратко изложу - потоки и процессы распараллеливают код, потоки удобны коммуникацией межу основным потоком и дочерними, но они не приспособлены к нагруженным действиям. Процессы это изолированный код , поэтому на них не распространяется GIL и как следствие они способны “держать” нагрузку.
Отредактировано Galvanize (Март 16, 2014 11:09:54)
Офлайн
253
GalvanizeЧтобы вы этим хотели сказать? Комфортной работы ядер? Разработчика? Не совсем быстро по отношению к чему? Приведите 2 кода один быстрый а другой не совсем… Тогда можно будет и разбираться.
Но процессов должно быть по 2 на каждое ядро для комфортной работы, а это не совсем быстро.
Отредактировано doza_and (Март 16, 2014 11:50:14)
Офлайн
32
GalvanizeДа.
будет ли лучше сделать асинхронный однопоточный сканер, вместо многопоточного?
Офлайн
857
doza_andне, я запущу обычную работу со списком
Если вы будете запускать из питона долго работающие скомпилированные модули то получите значительное ускорение от применения threading.
def f(lst): lst.append(1)
#!/usr/bin/env python3 import timeit import threading def lf(lst): lst.append(1) def f1(): lst = [] lf(lst) lf(lst) def f2(): lst = [] lf(lst) t = threading.Thread(target=lf, args=(lst,)) t.start() t.join() def main(): t1 = timeit.Timer('f1()', 'from __main__ import f1') t2 = timeit.Timer('f2()', 'from __main__ import f2') for t in t1, t2: print(t.repeat(3, 10000)) if __name__ == '__main__': main()
[guest@localhost py]$ ./thread_сmp.py
[0.008367057002033107, 0.008361406002222793, 0.008245788998465287]
[2.177827506999165, 2.260574555999483, 2.182044921999477]
[guest@localhost py]$
#!/usr/bin/env python3 import timeit import threading def lf(lst): for i in range(10000): lst.append(i) def f1(): lst = [] lf(lst) lf(lst) def f2(): lst = [] lf(lst) t = threading.Thread(target=lf, args=(lst,)) t.start() t.join() def main(): t1 = timeit.Timer('f1()', 'from __main__ import f1') t2 = timeit.Timer('f2()', 'from __main__ import f2') for t in t1, t2: print(t.repeat(3, 100)) if __name__ == '__main__': main()
[guest@localhost py]$ ./thread_сmp.py
[0.31656129700058955, 0.3210945509999874, 0.32146822299910127]
[0.916342791999341, 0.9165670609982044, 0.8958057629970426]
[guest@localhost py]$
Отредактировано py.user.next (Март 17, 2014 12:03:09)
Офлайн