2010-02-01 3 views
6

Этот вопрос относится к нарушениям производительности, которые могут возникнуть или не возникнуть из-за большого количества спящих потоков python на веб-сервере.Python: штраф за спящие темы

Справочная информация: Я реализую интернет-магазин, используя django/satchmo. Требование относится к задержке платежа. Клиент может зарезервировать продукт и позволить третьему лицу оплатить его позднее (с помощью случайного и уникального URL-адреса).

Чтобы обрабатывать неуправляемый предмет, я создаю поток, который будет спать в течение времени резервирования, а затем удалите резервирование/отметьте продукт как проданный при его пробуждении. Это выглядит следующим образом:

#Reserves a product when it is placed in the cart 
def reserve_cart_product(product): 
    log.debug("Reserving %s" % product.name) 
    product.active = False 
    product.featured = False 
    product.save() 
    from threading import Timer 
    Timer(CART_RESERVE_TIME, check_reservation, (product,)).start() 

Я использую ту же технику, когда забой уникальных URL-адрес после того, как они истекли, только таймер спит гораздо дольше (обычно 5 дней).

Итак, мой вопрос к вам SO выглядит следующим образом:

Оказывает большое numnber сонной темы собирается серьезно повлиять производительность? Существуют ли лучшие методы для планирования одного события в будущем. Я хотел бы сохранить это в python, если это возможно; без звонка at или cron через sys.

Сайт не является точным высоким трафиком; (щедрый) верхний предел для товаров, заказанных в неделю, будет около 100. В сочетании с резервированием тележки это может означать, что в каждый момент времени существует более 100 спальных нитей. Буду сожалеть о планировании задач таким образом?

Thanks

+1

Возможно, вам понадобится более устойчивое решение, чем потоки, если ваш сервер опустится. Насколько я могу судить, вам придется искать файл журнала, чтобы сообщить, какие продукты были зарезервированы после сбоя (хотя вы не знаете, как долго они были зарезервированы для вышеуказанного кода). – tgray

+0

Вы делаете хороший момент, и именно по этой причине я начал хранить некоторую запись в БД. – pisswillis

+0

Вы предполагаете, что ваш сервер не перезапустится, и вы не получите тысячи заказов, не так ли? Более надежным вариантом будет постоянная система очередности баз данных, такая как RabbitMQ. –

ответ

7

Я не вижу причин, почему это не должно работать. В базовом коде для Timer (в threading.py) просто используется time.sleep. Как только он ждал некоторое время, он в основном запускает цикл с time.sleep (0.05). Это должно привести к тому, что использование ЦП будет в основном 0%, даже с сотнями потоков. Вот простой пример, когда я заметил, 0% использование центрального процессора для процесса питона:

import threading 

def nothing(): 
    pass 

def testThreads(): 
    timers = [threading.Timer(10.0, nothing) for _ in xrange(881)] 
    print "Starting threads." 
    map(threading.Thread.start, timers) 
    print "Joining threads." 
    map(threading.Thread.join, timers) 
    print "Done." 

if __name__ == "__main__": 
    testThreads() 

Реальная проблема заключается в том, что вы не можете быть в состоянии фактически начать слишком много потоков. В моей 64-битной системе 4 Гбайт я могу начать только 881 поток, прежде чем я получу ошибку. Если у вас действительно будет всего несколько сотен, я не могу себе представить, что это не сработает.

3

Обычно спальные потоки не имеют накладных расходов, кроме памяти, выделенной для их стеков и других частных данных. Современные алгоритмы планирования операционной системы имеют сложность O (1), поэтому даже работающий поток не вводит накладные расходы, кроме памяти. В то же время трудно представить эффективный дизайн, требующий много потоков. Только случай, который я могу представить, - это общение со многими другими сверстниками. В этом случае следует использовать асинхронный IO.

4

100 нитей не проблема, но как tgray pointed out, что произойдет, если сервер опустится (выключение питания, плановое обслуживание, отказ оборудования и т. Д.)?

Вам нужно сохранить информацию о резервировании в своей базе данных где-нибудь.

Тогда вы можете заставить задание cron периодически запускать сценарий резервирования, например, и вам не нужно, чтобы все эти потоки сидели.

Если вы действительно не хотите использовать cron, у вас есть только один рабочий поток, который спит в течение минуты, а затем проверяет, не вызвано ли какое-либо из неуважений.

Смежные вопросы