сценарий Python может знать, что другой экземпляр того же сценария выполняет …, и затем говорите с ним?

Я хотел бы предотвратить несколько экземпляров того же продолжительного сценария командной строки Python от выполнения одновременно, и я хотел бы, чтобы новый экземпляр смог отправить данные в исходный экземпляр, прежде чем новый экземпляр совершит самоубийство. Как я могу сделать это межплатформенным способом?

А именно, я хотел бы включить следующее поведение:

  1. "foo.py"запускается из командной строки, и это будет оставаться рабочим в течение долгого времени - дни или недели, пока машина не будет перезагружена, или родительский процесс уничтожает его.
  2. каждые несколько минут тот же сценарий запускаются снова, но с различными параметрами командной строки
  3. при запуске сценарий должен видеть, работают ли какие-либо другие экземпляры.
  4. если другие экземпляры работают, то экземпляр № 2 должен отправить свои параметры командной строки для инстанцирования № 1, и затем экземпляр № 2 должен выйти.
  5. экземпляр № 1, если это получает параметры командной строки от другого сценария, должен вращать новый поток, и (использование параметров командной строки, отправленных на шаге выше), начинают выполнять работу, которую экземпляр № 2 собирался выполнить.

Таким образом, я ищу две вещи: как программа Python может знать, что другой экземпляр себя работает, и затем как одна программа командной строки Python может общаться с другим?

Делая это более сложным, тот же сценарий должен работать и на Windows и на Linux, таким образом, идеально решение пользовалось бы только библиотекой стандарта Python и не любыми определенными для ОС вызовами. Хотя, если у меня должен быть путь выполнения кода Windows и *, отклоняют путь выполнения кода (и большое if оператор в моем коде для выбора один или другой) это в порядке, если "тот же код" решение не возможен.

Я понимаю, что мог, вероятно, разработать основанный на файле подход (например, экземпляр № 1 смотрит каталог за изменениями, и каждый экземпляр бросает файл в тот каталог, когда он хочет сделать работу), но я немного обеспокоен чисткой тех файлов после некорректного завершения работы машины. Я идеально смог бы использовать решение в оперативной памяти. Но снова я гибок, если подход persistent-file-based является единственным способом сделать это, я открыт для той опции.

Подробнее: Я пытаюсь сделать это, потому что наши серверы используют контрольный инструмент, который поддерживает запускающие скрипты Python для сбора данных мониторинга (например, результаты вызова запроса или веб-сервиса базы данных), который контрольный инструмент затем индексирует для более позднего использования. Некоторые из этих сценариев являются очень дорогими для запуска, но дешевый для погони за запуском (например, создание соединения с БД по сравнению с выполнением запроса). Таким образом, мы приняли решение поддерживать в рабочем состоянии их в бесконечном цикле, пока родительский процесс не уничтожает их.

Это работает отлично, но на более крупных серверах могут работать 100 экземпляров того же сценария, даже если они только собирают данные каждые 20 минут каждый. Это наносит ущерб с RAM, пределами соединения с БД, и т.д. Мы хотим переключиться от 100 процессов с 1 потоком к одному процессу с 100 потоками, каждый выполняющий работу, которую, ранее, делал один сценарий.

Но изменение, как сценарии вызываются контрольным инструментом, не возможно. Мы должны сохранить вызов тем же (запустите процесс с различными параметрами командной строки), но но измените сценарии, чтобы распознать, что другой активен, и имейте "новый" сценарий, отправляют его рабочие инструкции (от параметрических усилителей командной строки) к "старому" сценарию.

BTW, это не что-то, что я хочу сделать на основе с одним сценарием. Вместо этого я хочу упаковать это поведение в библиотеку, которую многие авторы сценария могут усилить - моя цель состоит в том, чтобы позволить авторам сценария записать простые, однопоточные сценарии, которые не знают о проблемах мультиэкземпляра, и обработать многопоточность и единственное инстанцирование под покрытиями.

11
задан Justin Grant 29 May 2010 в 17:32
поделиться

4 ответа

Подход Алекса Мартелли к настройке канала связи является подходящим. Я бы использовал multiprocessing.connection.Listener для создания слушателя по вашему выбору. Документация по адресу: http://docs.python.org/library/multiprocessing.html#multiprocessing-listeners-clients

Вместо использования AF_INET (сокеты) вы можете выбрать AF_UNIX для Linux и AF_PIPE для Windows. Надеюсь, небольшое «если» не повредит.

Править : Думаю, пример не повредит. Хотя это базовый.

#!/usr/bin/env python

from multiprocessing.connection import Listener, Client
import socket
from array import array
from sys import argv

def myloop(address):
    try:
        listener = Listener(*address)
        conn = listener.accept()
        serve(conn)
    except socket.error, e:
        conn = Client(*address)
        conn.send('this is a client')
        conn.send('close')

def serve(conn):
    while True:
        msg = conn.recv()
        if msg.upper() == 'CLOSE':
            break
        print msg
    conn.close()

if __name__ == '__main__':
    address = ('/tmp/testipc', 'AF_UNIX')
    myloop(address)

Это работает в OS X, поэтому требует тестирования как с Linux, так и (после замены правильного адреса) с Windows. С точки зрения безопасности существует множество предостережений, главная из которых заключается в том, что conn.recv извлекает свои данные, поэтому вам почти всегда лучше использовать recv_bytes.

10
ответ дан 3 December 2019 в 05:56
поделиться

Может быть, попробовать использовать сокеты для связи?

1
ответ дан 3 December 2019 в 05:56
поделиться

Похоже, что лучше всего придерживаться файла pid, но пусть он не только содержит идентификатор процесса, но также включает номер порта, который прослушивает предыдущий экземпляр. Поэтому при запуске проверьте файл pid и, если он есть, посмотрите, запущен ли процесс с этим идентификатором - если да, отправьте ему свои данные и выйдите, в противном случае перезапишите файл pid с информацией о текущем процессе.

0
ответ дан 3 December 2019 в 05:56
поделиться

Общий подход заключается в том, чтобы скрипт при запуске устанавливал канал связи таким образом, чтобы он гарантированно был эксклюзивным (другие попытки установить тот же канал проваливаются предсказуемым образом), чтобы последующие экземпляры скрипта могли обнаружить, что первый запущен и общаться с ним.

Ваши требования к кроссплатформенной функциональности указывают на использование сокета в качестве канала связи: вы можете назначить "хорошо известный порт", зарезервированный для вашего скрипта, например 12345, и открыть сокет на этом порту, слушающий только localhost (127.0.0.1). Если попытка открыть этот сокет не удалась, потому что порт "занят", то вы можете подключиться к этому порту вместо него, и это позволит вам общаться с существующим скриптом.

Если вы не знакомы с программированием сокетов, есть хорошее HOWTO doc здесь. Вы также можете просмотреть соответствующую главу в Python in a Nutshell (я, конечно, отношусь к ней предвзято;-)).

9
ответ дан 3 December 2019 в 05:56
поделиться
Другие вопросы по тегам:

Похожие вопросы: