Python: сервер deferToThread XMLRPC - Twisted - Cherrypy? - PullRequest
0 голосов
/ 04 февраля 2010

Этот вопрос относится к другим, которые я задавал здесь, в основном касательно сортировки огромных наборов данных в памяти.

В основном это то, что я хочу / имею:

Запущен витой сервер XMLRPC. Этот сервер хранит несколько (32) экземпляров класса Foo в памяти. Каждый класс Foo содержит строку списка (которая будет содержать несколько миллионов записей). Существует служба, которая извлекает данные из базы данных и передает их на сервер XMLRPC. Данные в основном представляют собой словарь, ключи которого соответствуют каждому экземпляру Foo, а значения представляют собой список словарей, например:

data = {'foo1':[{'k1':'v1', 'k2':'v2'}, {'k1':'v1', 'k2':'v2'}], 'foo2':...}

Затем каждому экземпляру Foo передается значение, соответствующее его ключу, и словари Foo.bar обновляются и сортируются.

class XMLRPCController(xmlrpc.XMLRPC):

    def __init__(self):
        ...
        self.foos = {'foo1':Foo(), 'foo2':Foo(), 'foo3':Foo()}
        ...

    def update(self, data):
        for k, v in data:
            threads.deferToThread(self.foos[k].processData, v)

    def getData(self, fookey):
        # return first 10 records of specified Foo.bar
        return self.foos[fookey].bar[0:10]

class Foo():

    def __init__(self):
        bar = []

    def processData(self, new_bar_data):
        for record in new_bar_data:
            # do processing, and add record, then sort
            # BUNCH OF PROCESSING CODE
            self.bar.sort(reverse=True)

Проблема в том, что когда функция обновления вызывается в XMLRPCController с большим количеством записей (скажем, 100K +), она перестает отвечать на мои вызовы getData, пока все 32 экземпляра Foo не завершат метод process_data. Я думал, что deferToThread сработает, но я думаю, что неправильно понимаю, в чем проблема.

Любые предложения ... Я открыт для использования чего-то другого, например Cherrypy, если оно поддерживает это требуемое поведение.


EDIT

@ Трой: Так устроен реактор

reactor.listenTCP(port_no, server.Site(XMLRPCController)
reactor.run()

Что касается GIL, было бы целесообразно изменить sys.setcheckinterval () значение к чему-то меньшему, поэтому блокировка данных снимается, чтобы ее можно было прочитать?

Ответы [ 2 ]

1 голос
/ 04 февраля 2010

Самый простой способ заставить приложение реагировать на запросы - разбить процессорные ресурсы на более мелкие куски, позволяя витому реактору работать между ними. Например, вызвав реактор.callLater (0, process_next_chunk), чтобы перейти к следующему фрагменту. Эффективная реализация совместной многозадачности самостоятельно.

Другим способом было бы использовать отдельные процессы для выполнения работы, тогда вы получите выгоду от нескольких ядер. Взгляните на Ampoule: https://launchpad.net/ampoule Он предоставляет API, аналогичный deferToThread.

0 голосов
/ 04 февраля 2010

Я не знаю, как долго работает ваш метод processData и как вы настраиваете ваш витой реактор. По умолчанию витой реактор имеет пул потоков от 0 до 10 потоков. Возможно, вы пытаетесь отложить до 32 длительных вычислений до 10 потоков. Это неоптимально.

Вам также нужно спросить, какую роль играет GIL в обновлении всех этих коллекций.

Edit: Прежде чем вносить какие-либо серьезные изменения в вашу программу (например, вызывать sys.setcheckinterval()), вам, вероятно, следует запустить ее с помощью профилировщика или модуля трассировки python. Они должны сказать вам, какие методы используют все ваше время. Без правильной информации вы не сможете внести правильные изменения.

...