Рубрики
Без рубрики

«Скорость» в Async Web Frameworks

Это было одновременно опубликовано в моем блоге на выходных по 2020-06-06 / 07, P … Tagged Patterson P … Tagged с Python, WebDev, Async, программированием.

Это было одновременно опубликовано на моем блог

На выходных из 2020-06-06/07, пост Cal Patterson «Async Python не быстрее» Выскочил на моем радаре на нескольких агрегаторах связи. Я согласен – Async Python не «быстрее», но у меня есть некоторые мысли о себе на эту тему.

Начнем у меня есть несколько предостережений: а) Я не разработчик эксперта б) Я не эксперт на Async C) Я связан с проектом Sanic, веб-каркас Python Async

С учетом того, что я хотел бы немного поговорить о ценности неблокирующих IO очень простой способ.

Рассмотрим это (и да, это тоже немного нереально): вы голодны. Вы решаете, что хотите есть пять гамбургеров, чтобы наделиться своим голодом. Чтобы получить эти гамбургеры, вы идете на ближайший ресторан быстрого обслуживания (Mcsynchronous’s или Micky Sync’s) и закажите их.

Этот ресторан имеет один повар, и этот повар имеет только способность сделать один гамбургер за один раз. Это не отличная настроек, но это делает работу. Требуется некоторое время, чтобы приготовить каждую гамбургер и собирать бургер, но для того, чтобы облегчить вас, ресторан даст вам каждый гамбургер, как только он будет готов. Предполагая, что каждый бургер занимает две минуты, чтобы сделать и собрать, через десять минут у вас будет все ваши гамбургеры.

Это похоже на следующее:

(1) order
(2) start burger 
(3) prep burger (two minutes)
(4) deliver burger 
(5) repeat steps 2 through 4 four times

Общее время: десять минут.

Вниз по улице – еще один сустав (этот называется async & await Burger), который также имеет один повар, но этот повар имеет возможность приготовить несколько гамбургеров одновременно. Для этого повара требуется две минуты для подготовки каждого гамбургера, но поскольку повар имеет преимущество в том, что он имеет возможность совместно подготовить несколько гамбургеров, они могут быть доставлены быстрее. Это сделано, потому что повар не должен сосредоточиться на каждом бургере один за раз, но вместо этого может начать бургер, а затем начать следующий бургер, возвращаясь к каждому бургеру, как он закончен.

Это похоже на следующее:

(1) order
(2) start burgers 1-5
(3) prep burgers 1-5 (two minutes each, simultaneously)
(4) deliver burgers

Общее время: две минуты.

Наконец, давайте добавим ограничение на наш сценарий бургера: есть только способность подготовить один гамбургер за раз. В этом сценарии, несмотря на ваща, способный справиться с несколькими гаммами, это невозможно, и поэтому потребуется повар десять минут, как и в Micky Sync.

Представьте, однако, что вы хотите только один бургер. Оба «A & A и Micky Sync» занимают столько же времени, чтобы подготовиться только один бургер, поэтому вообще нет преимущества скорости.

Все это то же самое для синхронных и асинхронных веб-каркасов и их «скорость» в целом. Возможность одного процесса для обработки нескольких одновременных запросов является преимуществом асинхронных операций. Если вы размещаете синхронный или блокирующий запрос (нашу способность подготовить только один бургер за один раз, помнить) преимущество удалено.

Я выбрал два высокоценаруемых рамок Python, чтобы продемонстрировать это: Сокол служил Gunicorn и Starlette служил Увикорн. Код как на паритет, так как я могу сделать их для синхронного и асинхронного максимально:

Сокол:

import falcon
import time

class DefaultResource:
    def on_get(self, req, resp):
        """Handles GET requests"""
        time.sleep(5)
        resp.media = "200 OK"

falconapi = falcon.API()
falconapi.add_route('/', DefaultResource())

служить:

Приложение Gunicorn: Фальконапи

Starlette:

from starlette.applications import Starlette
from starlette.responses import PlainTextResponse
from starlette.routing import Route
import asyncio

async def default(request):
    await asyncio.sleep(5)
    return PlainTextResponse("200 OK")


starletteapi = Starlette(debug=True, routes=[
    Route('/', default),
])

служить:

Приложение Uvicorn: StarlettePi.

Чтобы проиллюстрировать это, я использовал простой (и старый) инструмент – AB, что делает 5 запросов одновременно следующим образом:

AB -N 5 -C 5 http://localhost: 8000//

Результаты для Сокола:

This is ApacheBench, Version 2.3 <$Revision: 1874286 $>
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).....done


Server Software:        gunicorn/20.0.4
Server Hostname:        localhost
Server Port:            8000

Document Path:          /
Document Length:        8 bytes

Concurrency Level:      5
Time taken for tests:   25.031 seconds
Complete requests:      5
Failed requests:        0
Total transferred:      795 bytes
HTML transferred:       40 bytes
Requests per second:    0.20 [#/sec] (mean)
Time per request:       25031.488 [ms] (mean)
Time per request:       5006.298 [ms] (mean, across all concurrent requests)
Transfer rate:          0.03 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.3      1       1
Processing:  5006 11014 6527.0  12515   20025
Waiting:     5005 11013 6527.2  12515   20024
Total:       5007 11014 6526.9  12516   20025
ERROR: The median and mean for the initial connection time are more than twice the standard
       deviation apart. These results are NOT reliable.

Percentage of the requests served within a certain time (ms)
  50%  10013
  66%  15018
  75%  15018
  80%  20025
  90%  20025
  95%  20025
  98%  20025
  99%  20025
 100%  20025 (longest request)

Результаты для Starlette:

This is ApacheBench, Version 2.3 <$Revision: 1874286 $>
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).....done


Server Software:        uvicorn
Server Hostname:        localhost
Server Port:            8000

Document Path:          /
Document Length:        6 bytes

Concurrency Level:      5
Time taken for tests:   10.007 seconds
Complete requests:      5
Failed requests:        0
Total transferred:      695 bytes
HTML transferred:       30 bytes
Requests per second:    0.50 [#/sec] (mean)
Time per request:       10007.417 [ms] (mean)
Time per request:       2001.483 [ms] (mean, across all concurrent requests)
Transfer rate:          0.07 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    1   0.5      1       1
Processing:  5003 5003   0.2   5003    5004
Waiting:     5002 5003   0.5   5003    5003
Total:       5003 5004   0.6   5004    5005

Percentage of the requests served within a certain time (ms)
  50%   5004
  66%   5005
  75%   5005
  80%   5005
  90%   5005
  95%   5005
  98%   5005
  99%   5005
 100%   5005 (longest request)

Наконец, Starlette с блокирующим вызовом (Time.sleep (5)) вместо await enyncio.sleep (5):

This is ApacheBench, Version 2.3 <$Revision: 1874286 $>
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).....done


Server Software:        uvicorn
Server Hostname:        localhost
Server Port:            8000

Document Path:          /
Document Length:        6 bytes

Concurrency Level:      5
Time taken for tests:   25.036 seconds
Complete requests:      5
Failed requests:        0
Total transferred:      695 bytes
HTML transferred:       30 bytes
Requests per second:    0.20 [#/sec] (mean)
Time per request:       25035.827 [ms] (mean)
Time per request:       5007.165 [ms] (mean, across all concurrent requests)
Transfer rate:          0.03 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    1   0.6      1       2
Processing:  5009 17023 6716.0  20026   20026
Waiting:     5007 17022 6716.5  20026   20026
Total:       5009 17024 6716.6  20028   20028

Percentage of the requests served within a certain time (ms)
  50%  20027
  66%  20028
  75%  20028
  80%  20028
  90%  20028
  95%  20028
  98%  20028
  99%  20028
 100%  20028 (longest request)

Как видите, это почти так же, как сокол.

С Web API, все редко это просто, и существуют и другие преимущества, которые можно найти с уровнем зрелости экосистемы (синхронные библиотеки, имели более длительное время, чтобы получить правильные вещи), и никогда не должен пропустить простоту использования, чтобы убедиться, что сделаны правильно, но общая идея выглядит следующим образом:

Большая часть «скорости» Async IO происходит от возможности выполнять дополнительную работу, а другая работа выполняется, но не нужно внимания. В простых тестах выше, это обслуживает базовый запрос Get, но это относится везде.

Оригинал: “https://dev.to/sjsadowski/speed-in-async-web-frameworks-196m”