Форум сайта python.su
skavansВполне может быть. Вас не устраивает общая скорость сканирования?
eventlet по каким-то причинам получился быстрее.. ниже привожу код, который я прогонял
Отредактировано Lexander (Янв. 27, 2014 00:29:11)
Офлайн
skavans> Какую библиотеку стоит использовать из множества (gevent, eventlet, coroutines, etc.)? … Вопросы сложности написания кода под конкретную библиотеку не рассматриваются…
1. socket + select = asyncore.
2. Если считаете что использовать низкоуровневые батарейки не спортивно, то посмотрите в сторону событийных движков, например, есть такой чудной зверь как Circuits. Так же на глаза попадались Pulsar и Pants. Есть ещё whizzer. Этот к сожалению не развивается, а тот экземпляр что я пробовал (то ли из git, то ли релизную версию) имел примитивные позорные ошибки на грани опечаток. Заинтересовал API, например в нём введено понятие протокола, сервера и пр., всё как у большого брата Twisted, только этот с сердцем на pyev. В принципе API подсмотрен у Twisted, это очевидно.
3. Есть легковестный микронитевой фреймворк Diesel с занятной архитектурой, жаль он тянет за собой кучу левого не нужного барахла, а так же с абстракцией у него не очень. Я взял его на вооружение, когда занимался своим велосипедом. Так же в один ряд с gevent, eventlet и concurrence не забываем поставить syncless.
Есть ещё маленькая полезняшка iowait, как раз по вашей теме, если select'ами брезгуите, всё же XXI век на дворе :-). И ещё blinker есть, приятная мелочушка для мелочей, это сигнальная тема, никак с сетью не связанная.
skavans> А в чем различия между вот таким переключением зеленого потока и асинхронностью? Везде же некоторое подобие event loop используется, я прав?
Да, вы правы. В событийных (Twisted) и потоковых (Eventlet) системах присутствует “event loop”, в первом случае он явный, во втором шифруется за блокирующими операциями, такими как recv, send, sleep и пр. (за вызовом таких блокирующих операцией скрывается select или libevent, libev, libuv с последующем переключением потока куда нужно). Потоковые должны быть медленнее и больше употреблять памяти из-за необходимости хранить стеки и переключать управление между потоками, но работать с ними зачастую проще/естественнее, чем с событийными.
Так же можете попробовать собрать Python без потоков, теоретически это может дать прирост.
..bw
Офлайн
bw, спасибо за развернутый ответ!
bw
1. socket + select = asyncore.
2. Если считаете что использовать низкоуровневые батарейки не спортивно,
import socket from iptools import IpRange import asyncore class ConnectionTester(asyncore.dispatcher): def __init__(self, host): asyncore.dispatcher.__init__(self) self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.socket.settimeout(5) self.connect( (host, 80) ) def handle_connect(self): print 'ok' def handle_error(self): print 'bad' guys = [ConnectionTester(ip) for ip in IpRange('62.64.64.0', '62.64.64.5')] asyncore.loop()
Офлайн
Что вы конкретно под последовательно выполняете? Вы ведь не думаете, что если вы с двух реальных ядер CPU, сделав два одновременных (с точностью syscall-а до такта) обращения к ядру системы (допустим что ядро так же работает на двух CPU), получите два одновременных соединения? Вынужден ваз разочаровать, ядро не однократно прибегнет к блокировке (если оно вообще в несколько потоков работает) на разных уровнях что приведёт к последовательной посылке датаграм по eth. Но подозреваю, что вы это и так понимаете.
Вы про select (мультиплексный ввод-вывод) слышали?
Неблокируемый сокет не блокирует поток в момент блокирующего обращения к ядру.
Попробуйте settimeout убрать, а так код в порядке, должен работать лучше чем Eventlet. Получилось на каком уровне в сравнении с другими вариантами?
p.s. Можно ещё книжку Р.Стивенса “UNIX разработка сетевых приложений” почитать.
..bw
Офлайн
bw, понимаю, конечно дело в том, что таймаут мне убрать нельзя - отключение по таймауту входит в постановку задачи.
Проблема в том, что если в handle_connect выполнять некоторые блокирующие операции (например, получение содержимого страницы), то asyncore.loop() позволит выполнять это параллельно с нескольких сокетов (псевдопараллельно, если быть точнее). А вот псевдопараллельный connect с помощью asyncore у меня сделать не получилось. Потому что сокеты нужно сначала создать и законнектить, а потом уже запускать ioloop. Вот на микронитях или событиях получается и коннект параллелить, а asyncore такой возможности как-будто не дает
На select/poll/epoll вот еще не пробовал задачу решить, немного другими вещами сейчас занимаюсь, пока что вариант на eventlet устроил, но все равно хочется еще большей скорости достичь, поэтому все-таки попробую их применить.
P.S.: а без таймаутов все нормально работает в таком коде, псевдопараллельно. Просто, как я понял, методы сокета setblocking и settimeout - взаимозаменяемые, нельзя использовать их одновременно. Поэтому вроде как мне для данной задачи не подходят неблокирующие сокеты, а только event-looping или микронити.
Отредактировано skavans (Фев. 2, 2014 21:02:59)
Офлайн
> Потому что сокеты нужно сначала создать и законнектить, а потом уже запускать ioloop.
Соединение как и посыл/получение выполняется асинхронно (ниже ещё про это скажу).
> На select/poll/epoll вот еще не пробовал задачу решить
Уже попробовали – asyncore, eventlet, ну вы меня поняли ;-).
> Поэтому вроде как мне для данной задачи не подходят неблокирующие сокеты, а только event-looping или микронити.
Как я написал раньше, они всё равно на неблокирующих сокетах, даже если цикл фреймворка построен на libevent, libev или libuv, используются неблокирующие сокеты и select/poll/epoll.
Про settimeout я спросил так как что-то такое в памяти теплится, что они ломают неблокируемость самого соединения. И насколько я знаю все эти сетевые фреймворки не используют socket.settimeout для таймаутов, а реализовывают их (таймауты :-) самостоятельно.
..bw
Офлайн
bw, ну вот в случае моего кода на asyncore - соединение последовательное, генератор при создании объекта коннектит сокет. Последовательно Видимо, вся соль этих фреймворков в самостоятельной реализации таймаутов как раз.. а по поводу того, что не пробовал select etс. имел в виду, что не пробовал на низком уровне решить задачу с их помощью
Офлайн
Посмотрел исходники Python 2.7.3 (читать документацию не круто же :-), socket.settimeout делает сокет блокируемым. Это чисто питонячья фича. Можно попробовать вместо неё использовать SO_RCVTIMEO и SO_SNDTIMEO, правда на connect они не влияют. В принципе не очень сложно и свои таймауты сделать, если очень надо. По крайней мере меня бы это не остановило :-).
..bw
Отредактировано bw (Фев. 2, 2014 22:10:45)
Офлайн
bwЛучше называть как “зеленые потоки” что-б с обычными не путать.
… потоковых (Eventlet) системах присутствует “event loop”, … Потоковые должны быть медленнее и больше употреблять памяти из-за необходимости хранить стеки
bwЭто имеет значение, epoll более производительное, лучше работает с большым кол-вом соединений.
Как я написал раньше, они всё равно на неблокирующих сокетах, даже если цикл фреймворка построен на libevent, libev или libuv, используются неблокирующие сокеты и select/poll/epoll.
Офлайн
Не забывайте, что автор сейчас работает только с 1 ядром процессора.
Если есть запас пропускной способности сетевого интерфейса, уверен, при запуске зеленых нитей в нескольких потоках, будет прирост производительности.
Офлайн