同时处理多个请求并使用Klein Module Python返回结果

时间:2016-12-30 07:55:50

标签: python multithreading web-services twisted klein-mvc

  • 您好我正在为我的网络服务器使用 Klein Python模块。
  • 我需要将每个请求作为一个线程单独运行并且还需要 返回结果。
  • 但Klein等到单个请求处理完成后才会等待 另一个请求。
  • 我也尝试过使用来自扭曲模块的deferToThread。但它也 仅在第一次请求完成后处理请求。
  • 同样我也尝试了@inlineCallbacks方法,它也产生了 同样的结果。
  

注意:当没有任何东西可以返回时,此方法可以正常工作。   但我需要返回结果。

我在下面附上了一个示例代码段,

import time
import klein
import requests
from twisted.internet import threads

def test():
    print "started"
    x = requests.get("http://google.com")
    time.sleep(10)
    return x.text

app = klein.Klein()

@app.route('/square/submit',methods = ['GET'])
def square_submit(request):
    return threads.deferToThread(test)

app.run('localhost', 8000)

2 个答案:

答案 0 :(得分:1)

作为@ notorious.no suggested,该代码有效并且可以工作。 要证明这一点,请查看此代码

# app.py
from datetime import datetime
import json
import time
import random
import string
import requests
import treq
from klein import Klein
from twisted.internet import task
from twisted.internet import threads
from twisted.web.server import Site
from twisted.internet import reactor, endpoints

app = Klein()

def test(y):
    print(f"test called at {datetime.now().isoformat()} with arg {y}", )
    x = requests.get("http://www.example.com")
    time.sleep(10)

    return json.dumps([{
        "time": datetime.now().isoformat(),
        "text": x.text[:10],
        "arg": y
    }])

@app.route('/<string:y>',methods = ['GET'])
def index(request, y):
    return threads.deferToThread(test, y)

def send_requests():
    # send 3 concurrent requests
    rand_letter = random.choice(string.ascii_letters)
    for i in range(3):
        y = rand_letter + str(i)
        print(f"request send at {datetime.now().isoformat()} with arg {y}", )
        d = treq.get(f'http://localhost:8080/{y}')
        d.addCallback(treq.content)
        d.addCallback(lambda r: print("response", r.decode()))

loop = task.LoopingCall(send_requests)
loop.start(15) # repeat every 15 seconds

reactor.suggestThreadPoolSize(3)

# disable unwanted logs
# app.run("localhost", 8080)

# this way reactor logs only print calls
web_server = endpoints.serverFromString(reactor, "tcp:8080")
web_server.listen(Site(app.resource()))
reactor.run()

安装treq和klein并运行

$ python3.6 -m pip install treq klein requests
$ python3.6 app.py

输出应为

request send at 2019-12-28T13:22:27.771899 with arg S0
request send at 2019-12-28T13:22:27.779702 with arg S1
request send at 2019-12-28T13:22:27.780248 with arg S2
test called at 2019-12-28T13:22:27.785156 with arg S0
test called at 2019-12-28T13:22:27.786230 with arg S1
test called at 2019-12-28T13:22:27.786270 with arg S2
response [{"time": "2019-12-28T13:22:37.853767", "text": "<!doctype ", "arg": "S1"}]
response [{"time": "2019-12-28T13:22:37.854249", "text": "<!doctype ", "arg": "S0"}]
response [{"time": "2019-12-28T13:22:37.859076", "text": "<!doctype ", "arg": "S2"}]
...

如您所见,克莱因不阻止这些请求。

此外,如果将线程池大小减小到2

reactor.suggestThreadPoolSize(2)

Klein将执行前两个请求,并等待直到再次有空闲线程。

@ notorious.no建议的

“异步替代方案” 将在here中进行讨论。

答案 1 :(得分:0)

  

但是克莱因等到处理另一个请求的单个请求完成后才会等待。

事实并非如此。事实上,您提供的代码绝对没有错。只需在tcp:localhost:8000运行示例服务器并使用以下curl命令即可​​使您的声明无效:

curl http://localhost:8000/square/submit &    # run in background
curl http://localhost:8000/square/submit

假设您在网络浏览器中测试代码,我是否正确?如果你是,那么你正在体验一个&#34;功能&#34;最现代的浏览器。浏览器将在给定时间为每个URL发出单个请求。在浏览器中解决这个问题的一种方法是在URL的末尾添加一个伪造的查询字符串,如下所示:

http://localhost:8000/squre/submit
http://localhost:8000/squre/submit?bogus=0
http://localhost:8000/squre/submit?bogus=1
http://localhost:8000/squre/submit?bogus=2

但是,新的Twisted / Klein开发人员常常犯的一个常见错误就是编写阻塞代码,认为Twisted会神奇地使其异步。例如:

@app.route('/square/submit')
def square_submit():
    print("started")
    x = requests.get('https://google.com')    # blocks the reactor
    time.sleep(5)    # blocks the reactor
    return x.text

这样的代码将按顺序处理请求,并应使用异步备选方案进行修改。