Иногда бывает так, что нужно что бы программа выполнялась в фоне т.е. не была бы привязана к тому месту откуда была вызвана, например при написании демонов на UNIX системах и сервисоподобного ПО в Windows системах.
Вопросы создания процесса и его поведения достаточно отличаются в этих ОС. В случае с UNIX достаточно такого распространенного приема как "Magic double fork". В случае с Windows ОС дело обстоит сложнее, одним из вариантов является превратить процесс в службу (service) Windows, для этого можно воспользоваться библиотекой pywin32, которая за вас реализует цепочку вызовов Windows API. Однако это библиотека достаточно тяжела и избыточна функционалом, если необходимо решить только заданную задачу.
Суть варианта, рассматриваемого далее, состоит в том что на этапе инициализации (т.е. до запуска основного кода) происходит запуск дочерней идентичной программы и выходу из родительской. Таким образом дочерняя программа продолжает выполнение не имея стандартных потоков ввода/вывода.
import optparse, os, sys, platform, subprocess
class Main(object):
def __init__(self):
parser=optparse.OptionParser(
parser.add_option(
parser.add_option(
parser.add_option(
command_line_options, self.arguments=parser.parse_args()
if platform.system()==
try:
pid=os.fork()
if pid>0:
sys.exit(0)
except OSError, e:
sys.exit(1)
try:
pid=os.fork()
if pid>0:
sys.exit(0)
except OSError, e:
sys.exit(1)
else:
if not self.options.windows_daemon:
p=subprocess.Popen([sys.executable or
time.sleep(2)
if p.poll()!=None:
print p.stderr.read()
print p.stdout.read()
exit(1)
exit(0)
optparse Deprecated since version 2.7
ОтветитьУдалитьтакой подход с чтением из потоков может зависать, например, при чтении из stderr когда туда ничего не выводится
рабочий вариант сделать так
p=subprocess.Popen(['python']+sys.argv+['--windows-daemon'], shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
и читать всё из одного потока
а почему такая проверка на None? обычно проверяется is None/is not None
За пост спасибо, как раз искал как можно сделать службу из скрипта, но в основном встречал вариант с pywin32
>>optparse Deprecated since version 2.7
Удалитьтак то да, но почему то до сих пор он есть и в 3й ветке). Официально предпочтительнее использовать argparse.
>>такой подход с чтением из потоков может зависать, например, при чтении из stderr когда туда ничего не выводится
нет, если туда ничего не выводится он вернет пустую строку. Не забываем к тому же что по коду это уже завершенный процесс и следовательно все потоки (а ведь они файло-подобные объекты) закрыты. А ваш предложенный вариант плох, например когда приложение сложнее и вывод с потоком нужно далее как то обрабатывать (помним что не едином print'ом живы)
>>а почему такая проверка на None? обычно проверяется is None/is not None
ну как мне кажется это не принципиально, конструкция is это такой Питонячий подход, у меня же использован из классических ЯП. Ничего принципиального.
>>За пост спасибо
пожалуйста)
Да я не заметил что работа идёт с уже завершенным процессом. Но насколько я помню для этого используется communicate. Но при выводе с процесса который работает в данный момент, виснуть всё таки будет.
Удалить>>Но насколько я помню для этого используется communicate.
Удалитьвы плохо поняли код, вовсе не нужно ждать когда дочерняя программа завершит выполнение, что делает communicate или wait.
>>Но при выводе с процесса который работает в данный момент, виснуть всё таки будет.
ну виснет наверное не то слово, метод read() считывает все до тех пор пока не получит EOF, при работающей программе он его не получит. Следовательно, он будет считывать вывод до тех пор пока не получит EOF.
sys.executable
ОтветитьУдалитьспасибо=)До сих пор не знал о таком. Несколько напрягает указание о возможном возврате пустой строки, но думаю этот вариант выжмет максимум из возможного:
Удалитьsubprocess.Popen([sys.executable or 'python']+sys.argv+['--windows-daemon'] ...