Найти - Пользователи
Полная версия: twisted + multiprocessing
Начало » Python для экспертов » twisted + multiprocessing
1
simplecode
Здравствуйте!
Имеется сервер на twisted, к которому возможен доступ по HTTP:
web = internet.TCPServer(PORT, server.Site(resource))
Имеется несколько классов ресурсов, методы render_ которых нагружают CPU своими вычислениями на несколько секунд:
class AnyResource(resource.Resource):
    def render_GET(self, request):
        ...
        many_calculations()  # долгие вычисления на CPU
        ...
        return NOT_DONE_YET
Хотелось бы работу таких методов выделять в отдельный процесс.
На данный момент я смотрю в сторону: multiprocessing, spawnProcess и ampoule, но не совсем понимаю как с помощью каждого из этих инструментов грамотно построить архитектуру сервера.
Подскажите, что предпочтительней использовать и как грамотно это сделать.
Спасибо.
bw
Да к тож знает, какие у вас там “many_calculations”. Но `multiprocessing` я бы не использовал (как и `os.fork`), он не в тему, и могут возникнуть трудноуловимые проблемы из-за того что, если закрытие левых файловых дескрипторов проблем не представляет, то “чистить структуры” после форка та ещё задачка. Можно конечно форкнуть (например с помощью `multiprocessing`) детей в самом начале работы процесса, когда он максимально чист, настроить с ними контакт через `stdio`, например, но это геморрой на мой взгляд, нужно ли оно вам.

Если ресурсоёмкая задача хорошо разбивается на мелкие части, посмотрите так же в сторону `twisted.internet.task.coiterate` (и `twisted.application.internet.CooperatorService` для понту). Тут конечно не очень хорошо ресурсы процессора будут утилизированы, но не будет блокировок и может для ваших нужд хватит. Вещь довольно простая и минимум побочных эффектов, а вот в случае с `ampoule` или `spawnProcess` придётся поднапрячься.

..bw
simplecode
bw
Да к тож знает, какие у вас там “many_calculations”
Два вида, 1) например:
for i in xrange(10**8): k += i
2) рекурсивный обход некоторого дерева объектов с обращением к БД (SQLAlchemy) за данными этих объектов, т.е. обращений к БД в одной функции около нескольких десятков тысяч раз.

На stackoverflow имеются рекомендации в сторону ampoule. Twisted с multiprocessing использовать тоже не рекомендуют.
Ok, Начал разбираться с ampoule, создал команду и протокол:
class AnyCommand(amp.Command):
    arguments = [("n", amp.Integer())]
    response = [("response", amp.String())]
class AnyProtocol(child.AMPChild):
    @AnyCommand.responder
    def process(self, n):
        res = many_calculations(n)
        return {"response": resp}
и перенес ту самую many_calculations() в AnyProtocol, т.к. оставлять ее в render_GET нет никакого смысла.
Если это вычисления вида
for i in xrange(10**8): k += i
, то все ок, вычисления производятся в отдельном процессе и возвращается результат, а если это обращения к БД, то тут две проблемы:
- создание объекта сессии (вообще, как мне показалось проблема с импортом модулей в методе process)
- как описать возвращаемое значение в AnyCommand? Имеются типы amp.Integer(), amp.String(), а функция возвращает объект моего некоторого класса и размер этого объекта может быть больше 64 кБ
simplecode
Разбираюсь с ampoule.
Исходники примера (файлы main.py и worker.py):
https://bitbucket.org/simple-code/test_ampoule/src/9e8e631b9723bb0a1e14b40e3ec3a20610b4ac0f/main.py?at=default
Вопрос все тот же:
Как вернуть из AnyProtocol.protocol то значение, которое возвращает функция many_calculations? Или же придется переписать many_calculations, чтобы она возвращала, что-то понятное методу AnyProtocol.protocol (str для примера выше)?
bw
1) В `coiterate` можно запихнуть, если конечно в сам код можно внести изменения.
2) Может вообще в этой не имеет смысла использовать Twisted. Напишите “традиционный” скрипт и запускайте его через `spawnProcess`, общение с мастером через stdio. Какой-то сложный и большой результат должен возвращаться в мастер-процесс или что-то в стиле “хорошо”/“хреново”?

`amp.Integer`, `amp.String`, <напиши свой тип>. Если туда-сюда передаются сложные значения, всё равно придётся делать сериализацию, а куда она будет инкапсулирована, это вопрос вкусов/принципов/религии. В свой тип или куда-то ещё с использованием `amp.String` для приёма/передачи.

Код, в котором используется SQLAlchemy и обход дерева, требует ли Twisted? Думаю нет и использовать здесь `twisted.protocols.amp`, ampoule и Twisted вообще не целесообразно. Я бы запускал Свои скрипты, без движка Twisted через `spanProcess`, а ввод-вывод организовал через stdio. Если таких запусков много, то разумно не завершать процесс, а оставлять его ждать следующего обращения мастер-процесса. Так же можно создать пул таких дочерних работяг.

Опишите частоту обращения к (1) и (2) и формат/объём данных, которые передаются и возвращаются.

..bw
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB