Pull to refresh

Comments 30

Production server я бы перевёл как «рабочий сервер», в отличии от «сервера разработки» и «сервера сборки».
можно просто «боевой сервер», думаю многим будет понятно
Существуют чудесные фреймворки для разработки асинхронных приложений, такие как twisted — они позволяют абстрагироваться от деталей select/poll/epoll/что-там-еще-придумали-на-данной-платформе.
Где в статье написано, что это начало «убийцы» Twisted/Tornado/Diesel/etc?
Это описание того, как работает epoll в Linux.

А абстрагироваться от деталей позволяет libev/libevent.
> разрыв происходит не сразу же, а после нескольких последовательных таких холостых срабатываний, чтобы исключить возможность ошибочного определения.

Немного не понял Вашу мысль. Если epoll возвращает EPOLLIN, значит на сокете гарантированно есть события. Если данных нет, а событие есть — значит клиент закрыл соединение. Зачем тут делать лишние системные вызовы, это ведь, как-никак, лишние переключения контекста и трата ресурсов?
В моем примере и нет лишних вызовов. Речь же шла о том, что встречаются примеры подобного кода с несколькими проверками (2-3). Я решил, что стоит об этом написать.
А Вы не знаете, зачем авторы этих примеров делают несколько проверок, на какие ошибки рассчитывают?
В примерах данной статьи нет смысла использовать epoll вообще, так как мы сами блокируем сокет в строке
responses[connection.fileno()] = response
Мы не выходим из этой строки до тех пор пока не запишем в нее наш response. Те пока сервер пишет одному клиенту, он не обсуживает других. Убедится в этом можно записал в response строку на пару мегабайт, запустить сервер где нибудь не на локалхосте что бы скорость была не высока, а затем открыть две вкладки — сервер будет отвечеть только в одну из них, и только завершив, начнет во вторую. Те сокеты то ты опрашивем без форков, но конкурентой обработки в коде нет.
Все даже хуже оказалось, такак сокет не может быть готовым отправлять данные все время, то даже строку в 100кб пример передать не может, соединение рвется в призвольные моменты, ну и заблокированым остается как я и описал выше.
Проще всего убедится заменив
response += b'Hello, world!'
на
response += b'H!' * 2000
Это перевод, он дает представление о работе с epoll в целом.
Практический подход конкретно на python'е и на конкретных задачах я еще опишу в скором времени уже от себя.
Что-то не то вы говорите по-моему responses[connection.fileno()] = response — тут вроде вообще работы с сокетом не наблюдается.
Сейчас потестирую…
response_body = b'Hello, world!'*100000

response  = b'HTTP/1.0 200 OK\r\nDate: Mon, 1 Jan 1996 01:01:01 GMT\r\n'
response += b'Content-Type: text/plain\r\nContent-Length: '+str(len(response_body))+b'\r\n\r\n'
response += response_body

И длину очереди повыше постваил serversocket.listen(50). Результат:
$ ab -n 5000 -c 200 http://localhost:8081/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient)
Completed 500 requests
Completed 1000 requests
Completed 1500 requests
Completed 2000 requests
Completed 2500 requests
Completed 3000 requests
Completed 3500 requests
Completed 4000 requests
Completed 4500 requests
Completed 5000 requests
Finished 5000 requests


Server Software:        
Server Hostname:        localhost
Server Port:            8081

Document Path:          /
Document Length:        1300000 bytes

Concurrency Level:      200
Time taken for tests:   23.696 seconds
Complete requests:      5000
Failed requests:        0
Write errors:           0
Total transferred:      6500530000 bytes
HTML transferred:       6500000000 bytes
Requests per second:    211.01 [#/sec] (mean)
Time per request:       947.830 [ms] (mean)
Time per request:       4.739 [ms] (mean, across all concurrent requests)
Transfer rate:          267903.43 [Kbytes/sec] received

Connection Times (ms)
              min  mean[±sd] median   max
Connect:        0  134 956.2      0    9024
Processing:   136  293 474.7    212   13151
Waiting:        5  213 410.9    180   13140
Total:        137  427 1223.4    212   22161

Percentage of the requests served within a certain time (ms)
  50%    212
  66%    223
  75%    231
  80%    236
  90%    257
  95%   1477
  98%   3231
  99%   6137
 100%  22161 (longest request)

Если -c побольше ставить, то может и вывалиться
Дело не в валится/не валится. Вы запустите сервер, запустите ab как и делали. Потом в новом терминале запустите wget на этот же URL. Я ни разу не получил полный ответ, т.е. Hello, world!' повторенный 100 тыс раз.
Пруфпик:


Может Content-length неправильно прописали?
Правильно, видимо дело в версии питона. На 2.6.6 рвется на 3.2.1rc1 — работает.
Я на 2.7.1 запускал. Попробовал 2.6 — тоже нормально.

Но вообще довольно нестабильно работает 3-й пример. Например после отработки ab скрипт впадает в бесконечный цикл (т.е. i очень быстро инкрементируется, но при этом нормально отвечает на запросы). Если добавить код из примечаний переводчика (if not data:) то ок.
Ну и вылетает при высокой параллельности — нужно очередь увеличивать.
Извиняюсь за глупый вопрос, но что значит b перед строкой?
Строка байт, в отличие от строки в unicode u'...' или «сырой» r'...'.
Шикарно. Сэкономили кучу времени, спасибо.
Пардон, в статью пока некогда вникать сейчас, просто хочу заметить, что можно перевести «production server», как боевой сервер. Может и не совсем официально звучит, но суть отражает.
Спасибо, тема интересная. Но примеры очень сложно читать и понимать т.к. комментарии находятся далеко от кода. Понимаю что перевод, но может встроить комментарии прям в код — как обычные питоньи комментарии?
Если будут еще желающие на такой вариант и не будет, соответственно, армии противников — сделаю.
Писать комментарии к строчкам кода отдельно от кода используя нумерацию — это очень жестоко по отношению к читателям. Первые примеры еще более-менее воспринимаются, так как кода и комментариев мало и есть возможность охватить их почти без скроллинга страницы. Но вот третий пример — совершенно нечитаемый. В итоге просто прочитал комментарии, а потом просмотрел код. Как-то пытаться их соотносить по номерам — развлечение для особо терпеливых и собранных.

Если не трудно, поясните, для чего так было сделано?
В таком формате написан оригинал. Решил не менять уж порядка вещей, так как это перевод, а не пересказ.
В оригинале не ограничена длина строки текста, как это сделано на Хабре. Поэтому там это не столь сильно мешает, как здесь.
На этой неделе выложу «продолжение», в котором будет простой полнофункциональный пример. Уже не перевод, а отсебятина. Распишу в нем все в виде комментариев в коде.
Интересно можно ли использовать метод epoll что бы написать неблокирующий клиент используя httplib или urllib2, те делаем запросы сразу N URL,
получаем дескриптор сокета от данного объекта HTTPResponse.fileno() и засовываем в epoll.register
Для перевода существующего кода использующего urlllib и т.п., есть eventlet и gevent
Sign up to leave a comment.

Articles