Есть тестовое приложение:
import time
from flask import Flask
app = Flask(import_name=__name__)
@app.route('/')
def test():
time.sleep(5)
return 'ok'
Запускаю gunicorn так:
(VENV) p2mbot@mbp:~/projects/test/gt$ gunicorn --workers 10 --threads 10 gt:app
[2015-07-18 11:23:10 +0300] [13196] [INFO] Starting gunicorn 19.3.0
[2015-07-18 11:23:10 +0300] [13196] [INFO] Listening at: http://127.0.0.1:8000 (13196)
[2015-07-18 11:23:10 +0300] [13196] [INFO] Using worker: threads
[2015-07-18 11:23:10 +0300] [13199] [INFO] Booting worker with pid: 13199
[2015-07-18 11:23:10 +0300] [13200] [INFO] Booting worker with pid: 13200
[2015-07-18 11:23:10 +0300] [13201] [INFO] Booting worker with pid: 13201
[2015-07-18 11:23:10 +0300] [13202] [INFO] Booting worker with pid: 13202
[2015-07-18 11:23:10 +0300] [13203] [INFO] Booting worker with pid: 13203
[2015-07-18 11:23:10 +0300] [13204] [INFO] Booting worker with pid: 13204
[2015-07-18 11:23:10 +0300] [13205] [INFO] Booting worker with pid: 13205
[2015-07-18 11:23:10 +0300] [13206] [INFO] Booting worker with pid: 13206
[2015-07-18 11:23:10 +0300] [13207] [INFO] Booting worker with pid: 13207
[2015-07-18 11:23:10 +0300] [13208] [INFO] Booting worker with pid: 13208
Дальше в браузере одновременно открываю 5 вкладок этого тестового сайта. Я ожидаю, что эти вкладки в браузере отобразятся одновременно через 5 секунд, как задано в коде. Но они появляются поочередно, через каждые 5 секунд. Как будто работая все равно в один поток.
Что я делаю не так? :)
Ответ
Я могу воспроизвести поведение в Firefox и Google Chrome. Браузер выполняет только один запрос по заданной ссылке за раз.
Достаточно, использовать уникальные ссылки, чтобы увидеть, что gunicorn может обслуживать несколько запросов одновременно. Или вручную запустить несколько запросов (в этом случае не важно, одинаковые или разные ссылки).
Вот Питон скрипт, который выполняет несколько одновременных http-запросов и в то же время открывает те же ссылки в браузере:
#!/usr/bin/env python
import webbrowser
from multiprocessing.pool import ThreadPool
try:
from urllib2 import urlopen
except ImportError: # Python 3
from urllib.request import urlopen
urls = ['http://localhost:8000']*5 # same url
urls += ['http://localhost:8000?unique=' + str(i) for i in range(5)] # uniq. urls
pool = ThreadPool(len(urls) * 2)
# make requests concurrently
r = pool.map_async(lambda url: urlopen(url).read(), urls)
pool.map(webbrowser.open_new_tab, urls) # open tabs in a browser
r.get()
Для тестирования можно использовать, простое wsgi-приложение:
#file: wsgi_sleep.py
import itertools
import time
def app(environ, start_response, ids=itertools.count(1)):
status = '200 OK'
headers = [('Content-type', 'text/plain')]
data = "# request(s) per worker: " + str(next(ids))
headers.append(('Content-Length', str(len(data))))
start_response(status, headers)
time.sleep(5)
return [data]
Его можно запустить как:
$ gunicorn --threads 20 --access-logfile - wsgi_sleep:app
Результат
127.0.0.1 - - [18/Jul/2015:19:15:09 +0000] "GET / HTTP/1.1" 200 26 "-" "Python-urllib/2.7"
127.0.0.1 - - [18/Jul/2015:19:15:09 +0000] "GET / HTTP/1.1" 200 26 "-" "Python-urllib/2.7"
127.0.0.1 - - [18/Jul/2015:19:15:09 +0000] "GET / HTTP/1.1" 200 26 "-" "Python-urllib/2.7"
127.0.0.1 - - [18/Jul/2015:19:15:09 +0000] "GET / HTTP/1.1" 200 26 "-" "Python-urllib/2.7"
127.0.0.1 - - [18/Jul/2015:19:15:09 +0000] "GET /?unique=0 HTTP/1.1" 200 26 "-" "Python-urllib/2.7"
127.0.0.1 - - [18/Jul/2015:19:15:09 +0000] "GET /?unique=1 HTTP/1.1" 200 26 "-" "Python-urllib/2.7"
127.0.0.1 - - [18/Jul/2015:19:15:09 +0000] "GET / HTTP/1.1" 200 26 "-" "Python-urllib/2.7"
127.0.0.1 - - [18/Jul/2015:19:15:09 +0000] "GET /?unique=3 HTTP/1.1" 200 27 "-" "Python-urllib/2.7"
127.0.0.1 - - [18/Jul/2015:19:15:09 +0000] "GET /?unique=2 HTTP/1.1" 200 26 "-" "Python-urllib/2.7"
127.0.0.1 - - [18/Jul/2015:19:15:09 +0000] "GET /?unique=4 HTTP/1.1" 200 26 "-" "Python-urllib/2.7"
127.0.0.1 - - [18/Jul/2015:19:15:14 +0000] "GET / HTTP/1.1" 200 27 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:39.0) Gecko/20100101 Firefox/39.0"
127.0.0.1 - - [18/Jul/2015:19:15:14 +0000] "GET /?unique=2 HTTP/1.1" 200 27 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:39.0) Gecko/20100101 Firefox/39.0"
127.0.0.1 - - [18/Jul/2015:19:15:14 +0000] "GET /?unique=4 HTTP/1.1" 200 27 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:39.0) Gecko/20100101 Firefox/39.0"
127.0.0.1 - - [18/Jul/2015:19:15:14 +0000] "GET /?unique=1 HTTP/1.1" 200 27 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:39.0) Gecko/20100101 Firefox/39.0"
127.0.0.1 - - [18/Jul/2015:19:15:14 +0000] "GET /?unique=3 HTTP/1.1" 200 27 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:39.0) Gecko/20100101 Firefox/39.0"
127.0.0.1 - - [18/Jul/2015:19:15:14 +0000] "GET /?unique=0 HTTP/1.1" 200 27 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:39.0) Gecko/20100101 Firefox/39.0"
127.0.0.1 - - [18/Jul/2015:19:15:19 +0000] "GET / HTTP/1.1" 200 27 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:39.0) Gecko/20100101 Firefox/39.0"
127.0.0.1 - - [18/Jul/2015:19:15:24 +0000] "GET / HTTP/1.1" 200 27 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:39.0) Gecko/20100101 Firefox/39.0"
127.0.0.1 - - [18/Jul/2015:19:15:29 +0000] "GET / HTTP/1.1" 200 27 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:39.0) Gecko/20100101 Firefox/39.0"
127.0.0.1 - - [18/Jul/2015:19:15:34 +0000] "GET / HTTP/1.1" 200 27 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:39.0) Gecko/20100101 Firefox/39.0"
Лог показывает, что запросы от urllib клиента завершаются практически одновременно в то время как запросы от браузера для повторяющихся ссылок происходят последовательно (не связано с network.http.max-connections-per-server, возможно связано с настройками кэширования).
Комментариев нет:
Отправить комментарий