Есть ли способ Python запустить только один экземпляр программы?
Единственное разумное решение, которое я придумал, - это попытаться запустить его как сервер на каком-то порте, а затем вторая программа, пытающаяся привязаться к тому же порту, терпит неудачу. Но это не очень хорошая идея, может быть, есть что-то более легкое, чем это?
(Учтите, что иногда ожидается сбой программы, например segfault - поэтому такие вещи, как "файл блокировки" не будут работать)
python
process
locking
mutual-exclusion
Слава В
источник
источник
Ответы:
Следующий код должен выполнить эту работу, он кроссплатформенный и работает на Python 2.4-3.2. Я тестировал его в Windows, OS X и Linux.
Доступна последняя версия кода singleton.py . Пожалуйста, сообщайте об ошибках здесь .
Вы можете установить тендер одним из следующих способов:
easy_install tendo
pip install tendo
источник
Простое,
кросс-платформенноерешение, нашел в другом вопрос по Zgoda :Очень похоже на предложение С.Лотта, но с кодом.
источник
fcntl
Windows нет модуля (хотя функциональность можно эмулировать).fg
. Итак, похоже, что оно у вас работает правильно (т.е. приложение все еще активно, но приостановлено, поэтому блокировка остается на месте).lock_file_pointer = os.open(lock_path, os.O_WRONLY | os.O_CREAT)
Этот код специфичен для Linux. Он использует «абстрактные» доменные сокеты UNIX, но он прост и не оставляет устаревших файлов блокировки. Я предпочитаю это решение, потому что оно не требует специально зарезервированного TCP-порта.
Уникальную строку
postconnect_gateway_notify_lock
можно изменить, чтобы разрешить использование нескольких программ, которым требуется один экземпляр.источник
Я не знаю, достаточно ли он питонический, но в мире Java прослушивание определенного порта - довольно широко используемое решение, поскольку оно работает на всех основных платформах и не имеет проблем с аварийным завершением программ.
Еще одно преимущество прослушивания порта состоит в том, что вы можете отправить команду запущенному экземпляру. Например, когда пользователи запускают программу во второй раз, вы можете отправить запущенному экземпляру команду, чтобы он открыл другое окно (например, это то, что делает Firefox. Я не знаю, используют ли они порты TCP или именованные каналы или что-то вроде этого '').
источник
import socket; s = socket.socket(socket.AF_INET, socket.SOCK_STREAM); s.bind(('localhost', DEFINED_PORT))
.OSError
Будет повышена , если другой процесс связан с тем же портом.Никогда раньше не писал python, но это то, что я только что реализовал в mycheckpoint, чтобы предотвратить его запуск дважды или более crond:
Нашел предложение Slava-N после публикации в другом выпуске (http://stackoverflow.com/questions/2959474). Он вызывается как функция, блокирует исполняемый файл сценария (не файл pid) и поддерживает блокировку до завершения сценария (нормального или ошибочного).
источник
Используйте файл pid. У вас есть известное местоположение, «/ path / to / pidfile», и при запуске вы делаете что-то вроде этого (частично псевдокод, потому что я до кофе и не хочу так много работать):
Другими словами, вы проверяете, существует ли pid-файл; если нет, запишите свой pid в этот файл. Если pid-файл действительно существует, проверьте, является ли pid pid-идентификатором запущенного процесса; Если да, то у вас запущен еще один живой процесс, поэтому просто выключите его. Если нет, то предыдущий процесс потерпел крах, поэтому зарегистрируйте его, а затем запишите свой собственный pid в файл вместо старого. Тогда продолжай.
источник
Вы уже нашли ответ на аналогичный вопрос в другом потоке, поэтому для полноты картины посмотрим, как добиться того же в объединении Windows с именем mutex.
http://code.activestate.com/recipes/474070/
источник
Это может сработать.
Попытайтесь создать файл PID в известном месте. Если вы потерпели неудачу, кто-то заблокировал файл, все готово.
Когда вы закончите в обычном режиме, закройте и удалите файл PID, чтобы кто-то другой мог его перезаписать.
Вы можете заключить свою программу в сценарий оболочки, который удаляет файл PID, даже если ваша программа выйдет из строя.
Вы также можете использовать файл PID, чтобы убить программу, если она зависнет.
источник
Использование файла блокировки - довольно распространенный подход в unix. Если произойдет сбой, вам придется очистить его вручную. Вы можете сохранить PID в файле и при запуске проверить, есть ли процесс с этим PID, переопределив файл блокировки, если нет. (Однако вам также нужна блокировка вокруг файла read-file-check-pid-rewrite-file). Вы найдете то, что вам нужно для получения и проверки pid, в пакете os . Обычный способ проверить, существует ли процесс с данным pid, - отправить ему нефатальный сигнал.
Другими альтернативами могут быть комбинирование этого с семафорами flock или posix.
Открытие сетевого сокета, как предлагает saua, вероятно, будет самым простым и портативным.
источник
Для всех, кто использует wxPython для своих приложений, вы можете использовать
wx.SingleInstanceChecker
описанную здесь функцию .Я лично использую подкласс ,
wx.App
который делает использованиеwx.SingleInstanceChecker
и возвратFalse
изOnInit()
если есть существующий экземпляр приложения уже выполняется следующим образом:Это простая замена
wx.App
, запрещающая несколько экземпляров. Для того, чтобы использовать его просто заменитьwx.App
сSingleApp
в коде следующим образом:источник
Вот мое возможное решение только для Windows. Поместите следующее в модуль, возможно, с именем onlyone.py или как-нибудь еще. Включите этот модуль непосредственно в ваш __ main __ файл скрипта python.
объяснение
Код пытается создать мьютекс с именем, производным от полного пути к сценарию. Мы используем косую черту, чтобы избежать путаницы с реальной файловой системой.
преимущества
источник
Лучшее решение для этого в Windows - использовать мьютексы, как предлагает @zgoda.
В некоторых ответах используется
fctnl
(также входит в пакет @sorin teno), который недоступен в Windows, и если вы попытаетесь заморозить свое приложение python с помощью пакета, подобного тому,pyinstaller
который выполняет статический импорт, он выдает ошибку.Кроме того, использование метода файла блокировки создает
read-only
проблему с файлами базы данных (с этим сталкивалсяsqlite3
).источник
Я отправляю это как ответ, потому что я новый пользователь и Stack Overflow пока не позволяет мне голосовать.
Решение Сорина Сбарнеа у меня работает под OS X, Linux и Windows, за что я ему благодарен.
Однако tempfile.gettempdir () ведет себя одним способом под OS X и Windows, а другим - под другими some / many / all (?) * Nixes (игнорируя тот факт, что OS X также является Unix!). Для этого кода важна разница.
В OS X и Windows есть временные каталоги для конкретного пользователя, поэтому временный файл, созданный одним пользователем, не виден другому пользователю. Напротив, во многих версиях * nix (я тестировал Ubuntu 9, RHEL 5, OpenSolaris 2008 и FreeBSD 8) временный каталог для всех пользователей - / tmp.
Это означает, что когда файл блокировки создается на многопользовательской машине, он создается в / tmp, и только пользователь, который создает файл блокировки в первый раз, сможет запустить приложение.
Возможное решение - встроить текущее имя пользователя в имя файла блокировки.
Стоит отметить, что решение OP по захвату порта также будет некорректно работать на многопользовательской машине.
источник
Я использую
single_process
на своем Gentoo;пример :
см .: https://pypi.python.org/pypi/single_process/1.0
источник
Я продолжаю подозревать, что должно быть хорошее решение POSIXy, использующее группы процессов, без необходимости затрагивать файловую систему, но я не могу его понять. Что-то вроде:
При запуске ваш процесс отправляет «kill -0» всем процессам в определенной группе. Если такие процессы существуют, он завершается. Затем он присоединяется к группе. Никакие другие процессы не используют эту группу.
Однако это имеет состояние гонки - все несколько процессов могут делать это в одно и то же время, и все в конечном итоге присоединяются к группе и работают одновременно. К тому времени, когда вы добавите какой-то мьютекс, чтобы сделать его водонепроницаемым, вам больше не нужны группы процессов.
Это может быть приемлемо, если ваш процесс запускается cron только раз в минуту или каждый час, но меня немного беспокоит, что он пойдет не так именно в тот день, когда вы этого не хотите.
Я думаю, это не очень хорошее решение, если только кто-то не может его улучшить?
источник
Я столкнулся с этой проблемой на прошлой неделе, и, хотя я нашел несколько хороших решений, я решил сделать очень простой и чистый пакет Python и загрузил его в PyPI. Он отличается от teno тем, что может заблокировать любое строковое имя ресурса. Хотя можно, конечно, заблокировать,
__file__
чтобы добиться такого же эффекта.Установить с помощью:
pip install quicklock
Использовать его предельно просто:
Взгляните: https://pypi.python.org/pypi/quicklock
источник
Основываясь на ответе Роберто Росарио, я придумал следующую функцию:
Нам нужно определить глобальный
SOCKET
vaiable, поскольку он будет собираться мусором только после завершения всего процесса. Если мы объявим локальную переменную в функции, она выйдет из области видимости после выхода из функции, и сокет будет удален.Вся заслуга принадлежит Роберто Росарио, поскольку я только поясняю и уточняю его кодекс. И этот код будет работать только в Linux, как поясняет следующий цитируемый текст из https://troydhanson.github.io/network/Unix_domain_sockets.html :
источник
пример linux
Этот метод основан на создании временного файла, который автоматически удаляется после закрытия приложения. при запуске программы проверяем наличие файла; если файл существует (есть отложенное выполнение), программа закрывается; в противном случае он создает файл и продолжает выполнение программы.
источник
В системе Linux можно также запросить
pgrep -a
количество экземпляров, сценарий находится в списке процессов (опция -a показывает полную строку командной строки). НапримерУдалите,
-u $UID
если ограничение должно применяться ко всем пользователям. Отказ от ответственности: а) предполагается, что (базовое) имя скрипта уникально, б) могут быть условия гонки.источник
источник