Twisted 异步请求处理

2 投票
1 回答
2144 浏览
提问于 2025-04-17 06:25

我想知道怎么在Twisted里像在Node.js那样处理异步请求。

我写了一个Twisted的示例,但我的应用程序还是在等待一个长时间操作的结果(我用time.sleep来模拟这个过程)。

另外,我也不太明白怎么正确使用reactor.callLater。

这是我写的Twisted应用的示例。


from twisted.web import server
from twisted.web.resource import Resource
from twisted.internet import reactor
from twisted.internet.defer import Deferred
import time

class Hello(Resource):
    def getChild(self, name, request):
        if name == '':
            return self
        print name
        return Resource.getChild(self, name, request)

    def render_GET(self, req):
        d = Deferred()
        reactor.callLater(2, d.callback, None)
        d.addCallback(lambda _: self.say_hi(req))
        return server.NOT_DONE_YET

    def say_hi(self, req):
        req.setHeader("content-type", "text/html")
        time.sleep(5)
        req.write("hello!")
        req.finish()

class Hello2(Resource):
    isLeaf = True
    def render_GET(self, req):
        req.setHeader("content-type", "text/html")
        return "hello2!"

root = Hello()
root.putChild("2", Hello2())
reactor.listenTCP(8080, server.Site(root))
reactor.run()

补充:现在我想问的是怎么写同步代码?请给个例子。

1 个回答

4

你其实已经在做了... 有点。

你遇到的问题是,time.sleep() 是一个阻塞调用,这会让你的整个服务器停下来。

如果你把它当作网络输入输出(I/O)操作的替代品(比如 urllib),最好的选择通常是用 Twisted 来处理 I/O(比如 twisted.web.client.getPage),而不是试图去处理这个阻塞的代码。Twisted 有很多客户端库,这些库通常会给你一个 Deferred,你已经在处理这个了。

如果你把它当作真正等待的替代品,那么你可以创建一个 Deferred,它会用 deferLater 来等待。

如果你把它当作一些 CPU 密集型的操作(比如 PIL 图像编码,或者一个本地的 XML 解析器),或者是一个现有的本地/专有 I/O 层(比如 Oracle 或 MSSQL 数据库绑定),你不想重写它来正确使用 Twisted,那么你可以用 deferToThread 来调用它。

无论你怎么得到你的 Deferred,你几乎已经准备好处理它了。你只需要调整 say_hi 使其返回一个:

def say_hi(self, req):
    req.setHeader("content-type", "text/html")
    d = getADeferredSomehow()
    def done(result):
        req.write("hello!")
        req.finish()
    return d.addBoth(done)

撰写回答