Форум сайта python.su
На моем компьютере сутками работает GUI-программа (на Qt).
1. По таймеру (QTimer) запрашиваются (раз в несколько секунд) свежие данные с нескольких сайтов.
2. Все данные анализируются, а интересные данные отправляются на еще один сайт.
3. Все обращения в сеть идут через пул потоков. Это обязательно.
Хочу перенести на VPS, но опыта - ноль :)
Почитал про asyncore, twisted, python-daemon, signal, процессы-демоны и потоки-демоны… Теперь в голове полная каша :)
В примерах пишут как сделать сервер, который слушает порт, а мне нужен клиент.
Обязательные требования:
1. работа сутками без перезагрузок
2. start/stop из терминала
3. start с передачей параметров
4. stop c вызовом какой-нибудь функции для корректного завершения процесса
5. возможность реализовать пул потоков (для параллельной загрузки данных из сети)
Офлайн
вырезать из кода Qt (сделать чисто консольным). и сделать авто-запуск через cron. если вручную стартовать, то можно через nohup.
если kill не подходит для завершения процесса, тогда можно делать stop-file который будет ждать скрипт, или xml-rpc управление сделать в скрипте.
Офлайн
dimabestэто все необязательно, тем более что скрипт работает.
Почитал про asyncore, twisted, python-daemon, signal, процессы-демоны и потоки-демоны…
Офлайн
cron отпадает из-за минимального интервала - 1 минута, а мне нужно вплоть до 1 сек.
Офлайн
Играюсь с python-daemon, демон запускается без проблем. Как запустить таймер (threading.Timer) знаю, как сделать ThreadPool на очередях знаю. И там, и там ждем результат в бесконечных циклах, а как совместить 2 цикла? На горизонте маячат еще потоки и синхронизация…. :(
Офлайн
А какие конкретно трудности?
Имхо общая теория выглядит так:
1. Делаем демона. Можно сторонними разработками, а можно и самому написать через двойной fork. Имхо в 20 строк уложится можно. Примеров в инете много, теорию можно почитать у Стивенса.
2. Запускаем главный поток в котором устанавливаем таймер и запускаем пул потоков-обработчиков. Так же в этом потоке нужно подключить обработчик сигналов, чтобы ловить сигнал запуска и остановки. Почитать про это можно тут - http://docs.python.org/library/signal.html
3. Создаем очередь и по таймеру передаем туда задания. Каждый из потоков в пуле после обработки задания возвращает task_done.
4. После завершения всех очередей обрабатываем результаты, ждем конца таймера и запускаем все заново.
Вот статейка по очередям/потокам - http://keysolutions.ru/articles/osnovy-raboty-s-potokami-v-python
Но все конечно зависит от того как именно сделано у вас сейчас. Может быть там все проще. Плясать в любом случае надо от имеющихся материалов.
Офлайн
У меня сложнее:
есть список объектов Query.
1. По таймеру запускается функция, которая отбирает Query со статусом WAITING, и проверяет - не пора ли загрузить свежие данные.
2. Объекты Query, для которых найдены свежие данные меняют статус на PROCESSING. Затем для каждого запрашиваются дополнительные данные. Причем пока эти данные будут подгружатся, может пройти секунды 4 и таймер запустится для свободных Query еще 4 раза.
Скорость очень важна, никто никого не ждет. Собственно говоря, скорость - главная причина переноса программы на VPS, ведь сайты в америке, а программа в Киеве.
3. Когда все загружено, данные нужно проанализировать и сложить инетересные на другой сайт.
Вобщем таймер живет своей жизню, а пул потоков своей.
Мне пришла интересная идея:
1. Делаю демона, который запускает QCoreApplication() (точнее уже сделал, работает!)
Пул потоков и таймер работают как в GUI программе, ничего менять не нужно.
2. Запускаю поток, в котором слушаю порт. Зачем? Через порт можно посылать команды! - перезагрузить конфиги, остановить демона (вызвав QCoreApplication.exit(0))
Офлайн
dimabestне, cron только для первичного запуска скрипта. а дальше он по таймеру будет крутиться, вместо QTimer.
cron отпадает из-за минимального интервала - 1 минута, а мне нужно вплоть до 1 сек.
Отредактировано (Дек. 28, 2010 18:57:12)
Офлайн
Ха! Все получилось.
функция запуска приложения:
def main():
app = QCoreApplication(sys.argv)
d = MyDaemon()
d.run()
sys.exit(app.exec_())
context = daemon.DaemonContext(
stderr = open('/path/to/err.log', 'a+'),
# и другие параметры
# ......
)
with context:
main()
class Manager(QThread):
def __init__(self):
QThread.__init__(self)
self.srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.srv.bind((HOST, PORT))
def run(self):
while True:
self.srv.listen(1)
sock, addr = self.srv.accept()
cmd = sock.recv(64)
# и т.д.
Офлайн