2013-05-02 3 views
1

Я пишу webservice в Django для обработки потоков изображений/видео, но в основном это делается во внешней программе. Например:django (или wsgi) цепочка stdout из подпроцесса

  1. клиентские запросы для /1.jpg?size=300x200
  2. питон кода разборе 300x200 в Джанго (или другой WSGI приложение)
  3. питона вызовов convert (часть Imagemagick) с помощью subprocess модуля, с параметром 300x200
  4. convert читает 1.jpg с локального диска, конвертирует в размер соответственно
  5. Запись в файл temp
  6. Django buil DS HttpResponse() и прочитать все содержимое временного файла в качестве тела

Как вы можете видеть, весь темп файла процесс чтения-записи, то неэффективно. Мне нужен общий способ работы с подобными внешними программами, например, не только convert, но и другие, такие как cjpeg, ffmepg и т. Д. Или даже запатентованные двоичные файлы.

Я хочу осуществить это таким образом:

  1. питон получает стандартный вывод fd процесса convert ребенка
  2. цепи его WSGI гнездо FD для вывода

Я сделал моя домашняя работа, Google говорит, что такая нуль-копия может быть выполнена с системным вызовом splice(). но он недоступен в Python. Итак, как максимизировать производительность в Python для такого рода сценариев?

  1. Соединиться по вызову() используя ctypes?
  2. hack memoryview() или buffer()?
  3. Подпроцесс имеет stdout который имеет readinto(), smogло использовать это как-нибудь?
  4. Как мы можем получить номер fd для любого приложения WSGI?

Я добрая новичка к этим, любое предложение оценили, спасибо!

+0

Это будет довольно дорогое порождать подпроцесс для каждого запроса. Как насчет использования ['PIL'] (http://www.pythonware.com/products/pil/) в том же процессе, а также во избежание создания временного файла? – Aya

+0

1. Результат PIL не так хорош. 2. Я не имел в виду исключительно Imagemagick, но и другую внешнюю программу, ffmpeg, cjpeg и т. Д. – est

+0

1. Какой алгоритм масштабирования вы используете в ImageMagick? 2. Многие обычно используемые внешние программы имеют привязки Python, которые будут намного быстрее, чем нерестущие подпроцессы, например. [Pyffmpeg] (http://code.google.com/p/pyffmpeg/). – Aya

ответ

1

Я считаю, что WSGI действительно может обрабатывать fd как ответ interator

Пример 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 

Это wrapps на стандартный вывод, как ответ HTTP через трубу

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 во всех остальных случаях.

Для случая видео, если вы возвращаете транскодированный видеопоток, узким местом, вероятно, будет либо процессорное время, либо пропускная способность сети.

+0

Hi @Aya большое спасибо, но как вы, ребята, работаете с проблемой чтения и записи файла temp? Можно ли вообще этого избежать? – est

+1

Ну, это зависит от того, сколько данных вы ожидаете, и от интерфейса к программе. Для программ, которые способны сбрасывать свой вывод на stdout, достаточно анонимного канала. Вы можете обернуть вывод канала с помощью итератора, который вызывает 'read()', затем используйте ['StreamingHttpResponse'] (https://docs.djangoproject.com/en/dev/ref/request-response/#django.http. StreamingHttpResponse), чтобы разрешить сетевому сокету потреблять данные по какой бы то ни было скорости, которая будет зависеть от доступной пропускной способности. – Aya