Python Klein - неблокирующий API - PullRequest
1 голос
/ 18 октября 2019

Нужна помощь с Klein API для неблокирования. Это простое тестовое приложение:

# -*- coding: utf-8 -*-
import datetime
import json
import time
from klein import Klein

app = Klein()

async def delay(seconds):
    """Set some delay for test"""
    time.sleep(seconds)
    return "Works"

@app.route('/', branch=True)
async def main(request):
    some_data = await delay(5)

    return json.dumps([{
        "status": "200",
        "time": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
        "data": some_data
    }])

app.run("localhost", 8080)

Затем просто запустите мой server.py, а затем 2 запроса одновременно к http://127.0.0.1:8080/. Результаты:

[ { "status": "200", "time": "2019-10-18 20:57:16", "data": "Works" } ]
[ { "status": "200", "time": "2019-10-18 20:57:21", "data": "Works" } ]

5 секунд задержки между каждым ответом.

Вопрос:

Как заставить этот код работать с 2 запросами нав то же время, теперь он работает один за другим ...

Также пытался использовать twistd, результаты такие же

PYTHONPATH=. twistd --pidfile=apserver.pid -n web --class=api.resource --port tcp:8000:interface=0.0.0.0

Спасибо

1 Ответ

1 голос
/ 22 октября 2019

Итак, проблема в том, что ваша delay функция - это функция блокировки, потому что Python time.sleep - это блокировка. Подробнее об этом вы можете прочитать здесь .

Вы должны использовать task.deferLater, который вы можете рассматривать как неблокирующую функцию сна Twisted framework, аналогичноasyncio.sleep()

# app.py
import datetime
import json

import treq
from klein import Klein
from twisted.internet import task, reactor

app = Klein()

async def delay1(secs):
    await task.deferLater(reactor, secs)
    return "Works"

def delay2(secs):
    return task.deferLater(reactor, secs, lambda: "Works")

@app.route('/', branch=True)
async def main(request):
    some_data = await delay1(5)  # or some_data = await delay2(5) 

    return json.dumps([{
        "status": "200",
        "time": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
        "data": some_data
    }])

def send_requests():
    for i in range(2):
        print("request", datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
        d = treq.get('http://localhost:8080')
        d.addCallback(treq.content)
        d.addCallback(lambda x: print("response", x.decode()))

# send 2 concurrent requests every 10 seconds to test the code
repeating = task.LoopingCall(send_requests)
repeating.start(10, now=False)

app.run("localhost", 8080)

для запуска кода

$ pip3 install treq klein
$ python3 app.py

подождите 10 секунд и на выходе должно быть

2019-10-21 17:17:11-0400 [-] request 2019-10-21 17:17:11
2019-10-21 17:17:11-0400 [-] request 2019-10-21 17:17:11
2019-10-21 17:17:16-0400 [-] "127.0.0.1" - - [21/Oct/2019:21:17:16 +0000] "GET / HTTP/1.1" 200 67 "-" "-"
2019-10-21 17:17:16-0400 [-] "127.0.0.1" - - [21/Oct/2019:21:17:16 +0000] "GET / HTTP/1.1" 200 67 "-" "-"
2019-10-21 17:17:16-0400 [-] response [{"status": "200", "time": "2019-10-21 17:17:16", "data": "Works"}]
2019-10-21 17:17:16-0400 [-] response [{"status": "200", "time": "2019-10-21 17:17:16", "data": "Works"}]
...