Есть ли простой способ запустить фоновую задачу из скрипта Python CGI, не дожидаясь его завершения? - PullRequest
3 голосов
/ 21 сентября 2011

В Windows, то есть.

Я думаю, что ответ на этот вопрос заключается в том, что мне нужно создать службу Windows.Это кажется нелепо тяжелым для того, что я пытаюсь сделать.

Я просто пытаюсь собрать здесь небольшой прототип для моего менеджера, я не собираюсь нести ответственность за его производство ... на самом деле, он может даже никогда не БЫТЬ произведенным;это может быть просто кое-что, с чем несколько исследователей могут поиграть.

У меня есть CGI-скрипт, который получает файл для загрузки, сохраняет его во временном местоположении, а затем запускает фоновый процесс, чтобы выполнить серьезное сокращение числа.в файле.Затем некоторые вещи из Javascript бездействуют, вызывая другие CGI-скрипты, чтобы проверить состояние и обновить страницу по мере необходимости.

Все это работает, за исключением того, что проклятый веб-сервер не будет закрывать соединение, пока выполняется подпроцессБег.Я провел некоторый поиск, и кажется, что ответ на Unix состоит в том, чтобы сделать его демоном, но я застрял в Windows прямо сейчас, и я думаю, что ответ есть, чтобы сделать его службой Windows?!?Это кажется невероятно тяжелым, чтобы просто, знаете, запустить чертов процесс и затем закрыть соединение с сервером.

Это действительно единственный способ?

Редактировать: Хорошо, нашел здесь небольшой изящный взлом(выбор (3), который дает парень): Как полностью справиться с процессом в Perl CGI под IIS

Мне удалось изменить это, чтобы сделать его еще проще, и хотя этоэто решение Klugey, оно идеально подходит для быстрого и грязного маленького прототипа, который я пытаюсь создать.

Итак, у меня изначально был основной сценарий, который делал это:

subprocess.Popen("python.exe","myscript.py","arg1","arg2")

Что нене работает, как я описал.Вместо этого у меня теперь есть основной сценарий, который генерирует этот маленький кусочек Javascript, который запускается после полной загрузки документа:

$("#somecrap").load("launchBackgroundProcess.py", {arg1:"foo",arg2:"bar"});

, а затем launchBackgroundProcess.py выполняет подпроцесс.Popen.

ThisРешение никогда не масштабируется, поскольку оно все еще оставляет соединение браузера открытым в течение всего времени выполнения фоновой задачи.Но так как этот мелкий щеголь, которого я собираю, может может когда-нибудь иметь максимум двух одновременных пользователей (даже тогда, я сомневаюсь в этом), ресурсы не являются проблемой.Это позволяет пользователю просматривать главную страницу и получать обновления Javascript, даже несмотря на то, что http-соединение остается открытым без веской причины.

Спасибо за ответы!Если меня когда-нибудь попросят произвести это, я воспользуюсь ресурсами, которые рекомендует Профейн.

Ответы [ 4 ]

1 голос
/ 21 сентября 2011

Вы можете просто использовать вызов system, используя команду windows start.Таким образом, ваш скрипт на python не будет ждать завершения запущенной программы.

1 голос
/ 21 сентября 2011

Если у вас нет большого опыта в программировании Windows и вы не хотите просматривать документы MSDN - я вас не виню - вы можете попытаться получить копию канонического руководства Марка Хаммонда для всех вещи питон и windows. Это так или иначе никогда не устареет по многим из этих повторяющихся вопросов. Вместо запуска процесса с решением для каждой платформы вам, вероятно, будет лучше использовать модуль win32process. Глава 17 книги Хаммонда подробно описывает это, но вы, вероятно, могли бы получить все, что вам нужно, загрузив pywin ide (я думаю, он входит в комплект расширений Windows, который вы можете загрузить из pypi), и просмотрев справочные документы, которые есть на api для windows python. Вот пример использования API из проекта, над которым я недавно работал. На самом деле он может делать то, что вы хотите с небольшой адаптацией. Возможно, вы захотите сосредоточиться на CreationFlags. В частности, win32process.DETACHED_PROCESS «часто используется для выполнения консольных программ в фоновом режиме». Однако многие другие флаги доступны и удобно упакованы.

    if subprocess.mswindows:
        su=subprocess.STARTUPINFO()
        su.dwFlags |= subprocess._subprocess.STARTF_USESHOWWINDOW
    process = subprocess.Popen(['program', 'flag', 'flag2'], bufsize=-1,
              stdout=subprocess.PIPE, startupinfo=su)
1 голос
/ 21 сентября 2011

Самый простой, но не самый эффективный способ - просто запустить другой исполняемый файл Python

from subprocess import Popen 
Popen("python somescript.py")
0 голосов
/ 23 сентября 2011

CGI-скрипты запускаются со стандартным перенаправленным выводом либо напрямую в сокет TCP, либо в канал.Как правило, соединение не закрывается, пока дескриптор и все его копии не будут закрыты.По умолчанию подпроцесс наследует копию дескриптора.

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

Если подпроцесс находится в Perl, я думаю, что вы могли бы очень просто закрыть дескриптор:

close(STDOUT);

Если вы хотите запретить подпроцессу наследовать дескриптор, вы можете использовать функцию SetHandleInformation (если у вас есть доступ к Win32 API) или установить bInheritHandles в FALSE при вызове CreateProcess.Или закройте ручку перед запуском подпроцесса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...