1

我正在 Django 中编写一个 Web 服务来处理图像/视频流,但它主要是在外部程序中完成的。例如:

  1. 客户要求/1.jpg?size=300x200
  2. 300x200在 django(或其他 WSGI 应用程序)中解析 python 代码
  3. python调用convert(Imagemagick的一部分)使用subprocess模块,参数为300x200
  4. convert从本地磁盘读取 1.jpg,并相应地转换为大小
  5. 写入临时文件
  6. Django 构建HttpResponse()并读取整个临时文件内容作为正文

如您所见,整个临时文件读写过程是低效的。我需要一种通用的方法来处理类似的外部程序,不仅如此convert,还有其他类似cjpeg的,ffmepg等等,甚至是专有的二进制文件。

我想以这种方式实现它:

  1. python获取子进程fd的stdoutconvert
  2. 将其链接到 WSGI 套接字 fd 以进行输出

我已经完成了我的功课,谷歌说这种零拷贝可以通过系统调用来完成splice()。但它在 Python 中不可用。那么如何在这种情况下最大化 Python 的性能呢?

  1. ctypes使用?调用 splice()
  2. 破解 memoryview() 或 buffer() ?
  3. subprocess has stdoutwhich has readinto(),可以以某种方式使用吗?
  4. 我们如何获得任何 WSGI 应用程序的 fd 编号?

我对这些有点新手,任何建议表示赞赏,谢谢!

4

2 回答 2

1

如果目标是提高性能,您应该逐个检查瓶颈,而不是采取“一刀切”的方法。

对于这种convert情况,假设图像不是非常大,那么瓶颈很可能是为每个请求生成一个子进程。

我建议避免创建一个子进程和一个临时文件,并在 Django 进程中使用PIL类似这样的东西来完成整个事情......

import os
from PIL import Image
from django.http import HttpResponse

IMAGE_ROOT = '/path/to/images'

# A Django view which returns a resized image
# Example parameters: image_filename='1.jpg', width=300, height=200
def resized_image_view(request, image_filename, width, height):
    full_path = os.path.join(IMAGE_ROOT, image_filename)
    source_image = Image.open(full_path)
    resized_image = source_image.resize((width, height))
    response = HttpResponse(content_type='image/jpeg')
    resized_image.save(response, 'JPEG')
    return response

通过使用正确的缩放算法,您应该能够获得与 ImageMagick 相同的结果,这通常ANTIALIAS适用于重新缩放的图像小于原始大小的 50% 的情况,以及BICUBIC所有其他情况。

对于视频,如果您要返回转码的视频流,瓶颈可能是 CPU 时间或网络带宽。

于 2013-05-02T10:30:28.727 回答
1

我发现 WSGI 实际上可以处理一个fd作为交互器响应

示例 WSGI 应用程序:

def image_app(environ, start_response):
    start_response('200 OK', [('Content-Type', 'image/jpeg'), ('Connection', 'Close')])
    proc = subprocess.Popen([
        'convert',
        '1.jpg',
        '-thumbnail', '200x150',
        '-', //to stdout
    ], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    return proc.stdout

它通过管道将标准输出包装为 http 响应

于 2013-09-04T04:34:44.227 回答