Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/355.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 扭曲克莱因:同步行为_Python_Asynchronous_Twisted_Synchronous_Klein Mvc - Fatal编程技术网

Python 扭曲克莱因:同步行为

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

我之所以使用Twisted Klein,是因为框架的承诺之一是它是异步的,但我测试了我开发的应用程序,并编写了一些代码进行测试,框架行为似乎是同步的

测试服务器代码为:

# -*- 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