Python 扭曲克莱因:同步行为
我之所以使用Twisted Klein,是因为框架的承诺之一是它是异步的,但我测试了我开发的应用程序,并编写了一些代码进行测试,框架行为似乎是同步的 测试服务器代码为:Python 扭曲克莱因:同步行为,python,asynchronous,twisted,synchronous,klein-mvc,Python,Asynchronous,Twisted,Synchronous,Klein Mvc,我之所以使用Twisted Klein,是因为框架的承诺之一是它是异步的,但我测试了我开发的应用程序,并编写了一些代码进行测试,框架行为似乎是同步的 测试服务器代码为: # -*- encoding: utf-8 -*- import json import time from datetime import datetime from klein import Klein app = Klein() def setHeader(request, content_type): r
# -*- 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"
正如您所看到的,服务器正在阻止当前的执行,并且它似乎是以同步方式而不是异步方式工作的
我错过了什么
致以最诚挚的问候。您遗漏了许多重要的扭曲概念。关于同步行为,您是绝对正确的,Klein的行为类似于同步框架,如Flask或Baggle,如果您不显式使用异步函数(即)。在您的示例中,您没有使用任何异步功能,因此代码按顺序执行。查看这篇文章可以帮助您了解Klein和Twisted中异步的基础知识。作为对读者的提醒,延迟不会使您的代码神奇地异步您必须仔细设计以实现并行执行 使代码异步 让我们尝试修复代码,使其异步运行。我将分几节介绍这些概念。如果需要更多信息,请发表评论,我会解决它。让我们从所需的导入开始:
from klein import Klein
from twisted.internet import defer, reactor
setHeader()
接下来,让我们看看如何更改setHeader()
函数。request.setHeader
函数速度相当快,因此可以多次运行而不会出现严重阻塞。因此,可以使用一个函数,该函数生成一个带有回调的延迟的对象,该回调将设置各种头键/值对:
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()
将回调链接在一起,但没有详细说明。在本例中,回调函数是本地的\u setHeader()
,它只设置头。最后,函数将返回延迟的。如果您注意到,\u setHeader()
接受一个参数上一个\u结果
,现在我们忽略它们
cleanParams()
如果正在使用循环(for
或while
),通常最好使用内联回调来生成结果。使用此方法,您可以在不阻塞主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
和产生
。我想演示多种异步样式
克莱因航线
最后,让我们在路由中实际使用异步函数:
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()
设置标题,它显式返回一个延迟的
。你使用的是时间。睡眠(5)
,你无意中阻塞了整个反应堆回路。在Klein/Twisted中,如果您想在以后做某事,通常会使用callLater()
。最后,我们通过gatherResults()
等待延迟asyncClean
和asyncSetHeader
的结果,并将时间戳写入响应主体
最终代码
server.py
test.sh
谢谢你的回答。为了理解如何使用它,我将看到这个链接。@DarioGuajardo实际上回顾一下你的问题,你在异步编程的许多方面都大错特错了。我下班后会提供更深入的答案。请记住,Klein或Twisted框架不会让您的代码“神奇地”异步-
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)
curl -v -X GET http://localhost:12030/test/?hello=world\&foo=bar\&fizz=buzz