2

我正在使用 twisted.web 框架在 python 中编写一个应用程序,以使用 html 5 流式传输视频。

视频是通过服务器发送static.File('pathtovideo').render_GET() 的 问题是一次只能流式传输一个视频,因为它占用了整个过程。

无论如何都要使流式传输异步或非阻塞,无论哪个术语在这里都合适。

我尝试使用 deferToThread 但这仍然束缚了这个过程。

这是我当前使用的类,其中 Movie 是一个 ORM 表,而 mid 只是任意行的 id。

class MovieStream(Resource):
    isLeaf=True

    def __init__(self, mid):
        Resource.__init__(self)
        self.mid = mid

    def render_GET(self, request):
        movie = Movie.get(Movie.id == self.mid)
        if movie:
             defered = deferToThread(self._start_stream, path=movie.source), request=request)
             defered.addCallback(self._finish_stream, request)
             return NOT_DONE_YET
        else:
            return NoResource()
`
     def _start_stream(self, path, request):
         stream = File(path)
         return stream.render_GET(request)

     def _finish_stream(self, ret, request):
         request.finish()
4

1 回答 1

3

这段代码中看起来像阻塞的部分实际上是Movie.get调用。

调用_start_streamwith是不正确的,deferToThread因为_start_stream使用了 Twisted API(File以及任何File.render_GET用途),并且在反应器线程中使用 Twisted API 是非法的(换句话说,在你调用的函数中使用它们是非法的 with deferToThread)。

幸运的是,您可以删除使用deferToThread来修复该错误。

要解决Movie.get阻塞问题,您需要找到一种异步访问数据库的方法。也许使用deferToThread(Movie.get, Movie.id == self.mid)- 如果实现的数据库库Movie.get是线程安全的,那就是。

对于它的价值,您还可以render_GET通过在资源遍历层次结构中更早地移动数据库查找逻辑来避免 hijinx。

例如,我想您的 URL 看起来像/foo/bar/<movie id>. 在这种情况下,系统会为孩子/foo/bar请求资源。<movie id>如果您像这样实现该查找:

from twisted.web.resource import Resource
from twisted.web.util import DeferredResource

class MovieContainer(Resource):
    def getChild(self, movieIdentifier):
        condition = (Movie.id == movieIdentifier)
        getting = deferToThread(Movie.get, condition)
        return DeferredResource(getting)

(假设这里Movie.get是线程安全的)那么你基本上就完成了。

资源遍历将以由构造的对象结束,DeferredResource(getting)当该对象被渲染时,它将负责等待getting结果(用术语来说,延迟到“触发”)并在其上调用正确的方法,例如render_GET,为请求生成响应。

于 2014-04-05T21:55:57.397 回答