我正在使用Twisted Klein,因为该框架的一个承诺是Asynchronous,但我测试了我开发的app和一些用于测试的代码,框架行为似乎是同步的。
测试服务器代码是:
# -*- encoding: utf-8 -*-
import json
import time
from datetime import datetime
from klein import Klein
app = Klein()
def setHeader(request, content_type):
request.setHeader('Access-Control-Allow-Origin', '*')
request.setHeader('Access-Control-Allow-Methods', 'GET')
request.setHeader('Access-Control-Allow-Headers', 'x-prototype-version,x-requested-with')
request.setHeader('Access-Control-Max-Age', 2520)
request.setHeader('Content-type', content_type)
def cleanParams(params):
for key in params.keys():
param = params[key]
params[key] = param[0]
return params
@app.route('/test/', methods=["GET"])
def test(request):
setHeader(request,'application/json')
time.sleep(5)
return json.dumps([str(datetime.now())])
if __name__ == "__main__":
app.run(host='0.0.0.0',port=12030)
测试请求是:
# -*- encoding: utf-8 -*-
import requests
from datetime import datetime
if __name__ == "__main__":
url = "http://192.168.50.205:12030"
params = {
}
print datetime.now()
for i in xrange(6):
result = requests.get(url + "/test/", params)
print datetime.now(), result.json()
启动服务器,如果我单独运行第二个代码:
2016-07-19 12:50:53.530000
2016-07-19 12:50:58.570000 [u'2016-07-19 12:50:58.548000']
2016-07-19 12:51:03.604000 [u'2016-07-19 12:51:03.589000']
2016-07-19 12:51:08.634000 [u'2016-07-19 12:51:08.625000']
2016-07-19 12:51:13.670000 [u'2016-07-19 12:51:13.654000']
2016-07-19 12:51:18.717000 [u'2016-07-19 12:51:18.708000']
2016-07-19 12:51:23.764000 [u'2016-07-19 12:51:23.748000']
完美,但如果我同时运行两个实例:
实例1:
2016-07-19 12:53:05.025000
2016-07-19 12:53:10.057000 [u'2016-07-19 12:53:10.042000']
2016-07-19 12:53:20.113000 [u'2016-07-19 12:53:20.097000']
2016-07-19 12:53:30.181000 [u'2016-07-19 12:53:30.166000']
2016-07-19 12:53:40.236000 [u'2016-07-19 12:53:40.219000']
2016-07-19 12:53:50.316000 [u'2016-07-19 12:53:50.294000']
2016-07-19 12:54:00.381000 [u'2016-07-19 12:54:00.366000']
实例2:
2016-07-19 12:53:05.282000
2016-07-19 12:53:15.074000 [u'2016-07-19 12:53:15.059000']
2016-07-19 12:53:25.141000 [u'2016-07-19 12:53:25.125000']
2016-07-19 12:53:35.214000 [u'2016-07-19 12:53:35.210000']
2016-07-19 12:53:45.270000 [u'2016-07-19 12:53:45.255000']
2016-07-19 12:53:55.362000 [u'2016-07-19 12:53:55.346000']
2016-07-19 12:54:05.402000 [u'2016-07-19 12:54:05.387000']
服务器输出:
2016-07-19 12:53:10-0400 [-] "192.168.50.205" - - [19/Jul/2016:16:53:04 +0000] "GET /test/ HTTP/1.1" 200 30 "-" "python-requests/2.9.1"
2016-07-19 12:53:15-0400 [-] "192.168.50.205" - - [19/Jul/2016:16:53:10 +0000] "GET /test/ HTTP/1.1" 200 30 "-" "python-requests/2.9.1"
2016-07-19 12:53:20-0400 [-] "192.168.50.205" - - [19/Jul/2016:16:53:15 +0000] "GET /test/ HTTP/1.1" 200 30 "-" "python-requests/2.9.1"
2016-07-19 12:53:25-0400 [-] "192.168.50.205" - - [19/Jul/2016:16:53:20 +0000] "GET /test/ HTTP/1.1" 200 30 "-" "python-requests/2.9.1"
2016-07-19 12:53:30-0400 [-] "192.168.50.205" - - [19/Jul/2016:16:53:25 +0000] "GET /test/ HTTP/1.1" 200 30 "-" "python-requests/2.9.1"
2016-07-19 12:53:35-0400 [-] "192.168.50.205" - - [19/Jul/2016:16:53:30 +0000] "GET /test/ HTTP/1.1" 200 30 "-" "python-requests/2.9.1"
2016-07-19 12:53:40-0400 [-] "192.168.50.205" - - [19/Jul/2016:16:53:35 +0000] "GET /test/ HTTP/1.1" 200 30 "-" "python-requests/2.9.1"
2016-07-19 12:53:45-0400 [-] "192.168.50.205" - - [19/Jul/2016:16:53:40 +0000] "GET /test/ HTTP/1.1" 200 30 "-" "python-requests/2.9.1"
2016-07-19 12:53:50-0400 [-] "192.168.50.205" - - [19/Jul/2016:16:53:45 +0000] "GET /test/ HTTP/1.1" 200 30 "-" "python-requests/2.9.1"
2016-07-19 12:53:55-0400 [-] "192.168.50.205" - - [19/Jul/2016:16:53:50 +0000] "GET /test/ HTTP/1.1" 200 30 "-" "python-requests/2.9.1"
2016-07-19 12:54:00-0400 [-] "192.168.50.205" - - [19/Jul/2016:16:53:55 +0000] "GET /test/ HTTP/1.1" 200 30 "-" "python-requests/2.9.1"
2016-07-19 12:54:05-0400 [-] "192.168.50.205" - - [19/Jul/2016:16:54:00 +0000] "GET /test/ HTTP/1.1" 200 30 "-" "python-requests/2.9.1"
正如您所看到的,服务器阻止当前执行,它似乎在同步而非异步。
我缺少什么?
最诚挚的问候。
答案 0 :(得分:4)
你错过了Twisted的许多重要概念。关于同步行为,你绝对正确,如果你没有明确地使用异步函数(即Deferreds
),Klein就像Flask或Bottle一样表现同步框架。在您的示例中,您没有使用任何异步功能,因此您可以按顺序执行代码。查看https://github.com/notoriousno/klein-basics/blob/intro/nonblocking.rst这可以帮助您了解Klein和Twisted中异步的基础知识。提醒读者延迟不要让你的代码神奇地异步!你必须仔细设计以实现并发执行。
让我们尝试修复您的代码,使其以异步方式运行。我将逐节介绍这些概念。如果需要更多信息,请发表评论,我将解决它。让我们从所需的导入开始:
from klein import Klein
from twisted.internet import defer, reactor
接下来让我们来看看setHeader()
功能。 request.setHeader
功能相当快,因此可以多次运行而不会出现严重阻塞。因此,可以使用生成Deferred
对象的函数,该对象具有将设置各种标题键/值对的回调:
def setHeader(request, content_type):
def _setHeader(previous_result, header, value):
request.setHeader(header, value)
d = defer.Deferred()
d.addCallback(_setHeader, 'Access-Control-Allow-Origin', '*')
d.addCallback(_setHeader, 'Access-Control-Allow-Methods', 'GET')
d.addCallback(_setHeader, 'Access-Control-Allow-Headers', 'x-prototype-version,x-requested-with')
d.addCallback(_setHeader, 'Access-Control-Max-Age', '2520')
d.addCallback(_setHeader, 'Content-type', content_type)
return d
我们没有详细介绍,我们正在使用Deferred.addCallback()
将回调链接在一起。在这种情况下,回调函数是本地_setHeader()
,它只是设置标题。最后,该函数将返回Deferred
。如果您注意到,_setHeader()
接受了previous_result
参数,请暂时忽略它们。
如果正在使用循环(for
或while
),通常最好使用inlineCallbacks
到yield
结果。使用此方法可以在不阻塞主ioloop的情况下以同步方式运行。
@defer.inlineCallbacks
def cleanParams(params):
for key in sorted(params):
param = params[key]
params[key] = yield param[0]
defer.returnValue(str(params)) # if py3 then use ``return params``
这是一个很糟糕的例子,但它应该说明如何使用yield
来等待一个值。另外,setHeader()
函数也可以使用inlineCallbacks
和yields
。我想演示多个异步样式。
最后,让我们实际使用路由中的异步函数:
app = Klein()
@app.route('/test/', methods=["GET"])
def test(request):
asyncClean = cleanParams(request.args)
asyncClean.addCallback(request.write)
asyncSetHeader = setHeader(request,'application/json')
reactor.callLater(5, asyncSetHeader.callback, None)
def render(results, req):
req.write(json.dumps([str(datetime.now())]))
finalResults = defer.gatherResults([asyncClean, asyncSetHeader])
finalResults.addCallback(render, request)
return finalResults
不要忘记!首先我们致电cleanParams()
,然后返回Deferred
,当它完成时,returnValue
将被写入反应机构。接下来,标题将通过setHeader()
设置,显式返回Deferred
。你使用的是time.sleep(5)
而你无意中阻塞了整个反应堆循环。在Klein / Twisted中,如果您想在以后做某事,通常会使用callLater()
。最后,我们通过asyncClean
等待延迟asyncSetHeader
和gatherResults()
的结果,并将时间戳写入响应正文。
server.py
import json
from datetime import datetime
from klein import Klein
from twisted.internet import defer, reactor
app = Klein()
def setHeader(request, content_type):
def _setHeader(previous_result, header, value):
request.setHeader(header, value)
d = defer.Deferred()
d.addCallback(_setHeader, 'Access-Control-Allow-Origin', '*')
d.addCallback(_setHeader, 'Access-Control-Allow-Methods', 'GET')
d.addCallback(_setHeader, 'Access-Control-Allow-Headers', 'x-prototype-version,x-requested-with')
d.addCallback(_setHeader, 'Access-Control-Max-Age', '2520')
d.addCallback(_setHeader, 'Content-type', content_type)
return d
@defer.inlineCallbacks
def cleanParams(params):
for key in sorted(params):
param = params[key]
params[key] = yield param[0]
defer.returnValue(str(params))
@app.route('/test/', methods=["GET"])
def test(request):
asyncClean = cleanParams(request.args)
asyncClean.addCallback(request.write) # write the result from cleanParams() to the response
asyncSetHeader = setHeader(request,'application/json')
reactor.callLater(5, asyncSetHeader.callback, None)
def render(results, req):
req.write(json.dumps([str(datetime.now())]))
finalResults = defer.gatherResults([asyncClean, asyncSetHeader])
finalResults.addCallback(render, request)
return finalResults
if __name__ == "__main__":
app.run(host='0.0.0.0',port=12030)
test.sh
curl -v -X GET http://localhost:12030/test/?hello=world\&foo=bar\&fizz=buzz