扭曲多个并发或异步流

时间:2014-04-05 16:50:44

标签: python html5 streaming twisted twisted.web

我使用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()

1 个答案:

答案 0 :(得分:3)

此代码看起来像阻止的部分实际上是Movie.get调用。

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

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

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

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

例如,我想您的网址看起来像/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得到一个结果(对于延迟为“fire”,在lingo)并在其上调用正确的方法,例如render_GET,以产生对请求的响应。