Python'da arka plan işlemi nasıl başlatılır?


295

Çok daha okunabilir python sürümüne bir kabuk komut dosyası için çalışıyorum. Orijinal kabuk betiği arka planda "&" ile birkaç işlem (yardımcı programlar, monitörler vb.) Başlatır. Python'da aynı etkiyi nasıl elde edebilirim? Python komut dosyaları tamamlandığında bu işlemlerin ölmemesini istiyorum. Bir şekilde bir daemon kavramıyla ilgili olduğundan eminim, ancak bunu nasıl kolayca yapabileceğimi bulamadım.



1
Merhaba Artem. Lütfen Dan'ın cevabını kabul edin, çünkü (1) daha fazla oy, (2) subprocess.Popen()2010'dan bu yana yeni önerilen yol (şimdi 2015'teyiz) ve (3) buraya yönlendirilen yinelenen sorunun da kabul edilmiş bir cevabı var subprocess.Popen(). Şerefe :-)
olibre

1
@olibre Aslında cevap uygun bir shebang subprocess.Popen("<command>")liderliğindeki <komut> dosyası ile olmalıdır . Benim için mükemmel çalışır (Debian), bash ve python betikleriyle, dolaysız shells ve ana sürecinden kurtulur. stdoutebeveynin terminaliyle aynı terminale gider. Yani bu &OP'nin isteği olan bir kabukta olduğu gibi çalışıyor . Ama cehennem, küçük bir test hiçbir zaman göstermezken tüm sorular çok karmaşık çalışır;)
flaschbier

Arka plan için ayrıca bkz. Stackoverflow.com/a/51950538/874188
tripleee

Yanıtlar:


84

Not : Bu yanıt 2009'da yayınlandığından daha az günceldir subprocess. Diğer yanıtlarda gösterilen modülü kullanmanız artık dokümanlarda önerilmektedir .

(Alt işlem modülünün yeni süreçleri oluşturmak ve sonuçlarını almak için daha güçlü özellikler sunduğunu unutmayın; bu modülü kullanmak bu işlevleri kullanmak için tercih edilir.)


İşleminizin arka planda başlamasını istiyorsanız, system()kabuk komut dosyanızla aynı şekilde kullanabilir ve çağırabilirsiniz veya şunları yapabilirsiniz spawn:

import os
os.spawnl(os.P_DETACH, 'some_long_running_command')

(veya alternatif olarak, daha az taşınabilir os.P_NOWAITbayrağı deneyebilirsiniz ).

Buradaki belgelere bakın .


8
Not: yürütülebilir dosyanın tam yolunu belirtmeniz gerekir. Bu işlev PATH değişkenini kullanmaz ve bunu kullanan değişken Windows altında kullanılamaz.
sorin

36
düz benim için python çöküyor.
pablo

29
os.P_DETACH, os.P_NOWAIT ile değiştirildi.
kendini

7
Kullanmayı öneren insanlar subprocessbize bir sürecin nasıl ayrılacağına dair bir ipucu verebilir subprocessmi?
rakslice

3
Bir arka plan işlemi bulmak ve IO'sunu yeniden yönlendirmek için Python komut dosyasını (diyelim attach.py) nasıl kullanabilirim, böylece attach.py ​​arka plandaki some_long_running_prog dosyasından okuyabilir / yazabilir?
raof01

376

Jkp'nin çözümü çalışırken , işleri yapmanın daha yeni yolu (ve belgelerin önerdiği yol) subprocessmodülü kullanmaktır . Basit komutlar için eşdeğerdir, ancak karmaşık bir şey yapmak istiyorsanız daha fazla seçenek sunar.

Davanız için örnek:

import subprocess
subprocess.Popen(["rm","-r","some.file"])

Bu rm -r some.filearka planda çalışacaktır . .communicate()Döndürülen nesneyi çağırmanın Popentamamlanıncaya kadar engelleneceğini unutmayın, bu nedenle arka planda çalışmasını istiyorsanız bunu yapmayın:

import subprocess
ls_output=subprocess.Popen(["sleep", "30"])
ls_output.communicate()  # Will block for 30 seconds

Buradaki belgelere bakın .

Ayrıca, bir açıklama noktası: Burada kullandığınız gibi "Arkaplan" tamamen bir kabuk konseptidir; teknik olarak, demek istediğin, bir işlemi tamamlamasını beklerken engellemeden yumurtlamak istiyorsun. Ancak, burada kabuk arka planı benzeri davranışı ifade etmek için "arka plan" kullandım.


7
@ Dan: Arka planda çalıştıktan sonra süreci nasıl öldürebilirim? Bir süre çalıştırmak (etkileşim kurduğum bir daemon) ve işimi bitirdiğimde öldürmek istiyorum. Dokümanlar yardımcı olmuyor ...
Juan

1
@Dan ama bunun için PID'yi bilmeme gerek yok mu? Etkinlik izleme / Görev yöneticisi bir seçenek değil (programlı olarak yapılması gerekir).
Juan

5
tamam Peki onun stdin yazmak için Popen () sonucuna ihtiyacınız olduğunda süreci arka plana zorlamak nasıl?
Michael

2
@JFSebastian: Bunu "mevcut programın yürütülmesini durdurmayan bağımsız bir süreci nasıl oluşturabilirim" olarak yorumladım. Bunu daha açık hale getirmek için düzenlememi nasıl önerirsiniz?
Dan

1
@Dan: doğru cevap: Popen()ana iş parçacığının engellenmesini önlemek için kullanın ve bir arka plan programına ihtiyacınız varsa , iyi tanımlanmış bir arka plan programının nasıl davranması gerektiğini anlamak için python-daemonpakete bakın . Alt işlem belgelerine bağlantı dışında "Dikkatli olun" ile başlayan her şeyi kaldırırsanız cevabınız tamam demektir.
jfs

47

Muhtemelen "Python'da harici bir komut nasıl çağrılır" cevabını istiyorsunuz .

En basit yaklaşım os.systemişlevi kullanmaktır , örneğin:

import os
os.system("some_command &")

Temel olarak, systemişleve ilettiğiniz her şey, bir komut dosyasında kabuğa geçirmiş olduğunuz gibi yürütülür.


10
IMHO, python betikleri genellikle çapraz platform olarak yazılır ve basit bir çapraz platform çözümü varsa, buna uymak daha iyidir. Gelecekte başka bir platformla çalışmanız gerekip gerekmediğini asla bilmeyeceksiniz :) Veya başka bir adam senaryonuzu platformuna taşımak isteyip istemediğini.
d9k

7
Bu komut eşzamanlıdır (yani her zaman başlatılan işlemin sonlandırılmasını bekler).
tav

@ d9k os.system taşınabilir değil mi?
lucid_dreamer

1
@ d9k, sizi posix-land'da konumlandıran arka planda bir şey çalıştırma seçeneği değil mi? Windows'da ne yapardınız? Hizmet olarak mı çalışıyorsunuz?
lucid_dreamer

Belirli bir klasörden bir komut çalıştırmam gerekirse bunu nasıl kullanabilirim?
mrRobot

29

Bunu burada buldum :

Pencerelerde (win xp), ana işlem tamamlanıncaya kadar longtask.pytamamlanmaz. CGI komut dosyasında istediğiniz gibi değil. Sorun Python'a özgü değildir, PHP topluluğunda problemler aynıdır.

Çözüm, DETACHED_PROCESS Proses Oluşturma BayrağınıCreateProcess win API'deki temel işleve geçirmektir . Pywin32'yi yüklediyseniz, bayrağı win32process modülünden içe aktarabilirsiniz, aksi takdirde kendiniz tanımlamanız gerekir:

DETACHED_PROCESS = 0x00000008

pid = subprocess.Popen([sys.executable, "longtask.py"],
                       creationflags=DETACHED_PROCESS).pid

6
İşlem kimliğinin nasıl saklanacağını göstermek için +1. Ve eğer birisi daha sonra işlem kimliğiyle programı öldürmek istiyorsa: stackoverflow.com/questions/17856928/…
iChux

1
Bu sadece Windows gibi görünüyor
Audrius Meskauskas

24

Kullanım subprocess.Popen()ile close_fds=Trueestiren altişlem Python kopmamak sağlayacak parametre, kendisini işlemek ve hatta Python çıkar sonra yayınlanmaya devam eder.

https://gist.github.com/yinjimmy/d6ad0742d03d54518e9f

import os, time, sys, subprocess

if len(sys.argv) == 2:
    time.sleep(5)
    print 'track end'
    if sys.platform == 'darwin':
        subprocess.Popen(['say', 'hello'])
else:
    print 'main begin'
    subprocess.Popen(['python', os.path.realpath(__file__), '0'], close_fds=True)
    print 'main end'

1
Pencerelerde, ayrılmaz ancak creationflags parametresi kullanılır
SmartManoj

3
Bu çözüm, Linux'ta Zombie olarak bir alt işlem bırakır.
TitanFighter

@TitanFighter, SIGCHLD SIG_IGN setiyle önlenebilir: stackoverflow.com/questions/16807603/…
sailfish009

teşekkürler @Jimmy Cevabınız SADECE çözüm benim için çalışıyor.
sailfish009

12

Muhtemelen farklı iş parçacıkları çatallamak için os modülünü araştırmaya başlamak istiyorsunuz (etkileşimli bir oturum açıp yardım (os) vererek). İlgili fonksiyonlar çatal ve exec fonksiyonlarından herhangi birisidir. Nasıl başlayacağınıza dair bir fikir vermek için, çatalı gerçekleştiren bir işleve böyle bir şey koyun (işlevin, programın adını ve parametrelerini içeren bir argüman olarak bir liste alması veya 'args' ifadesini alması gerekir; ayrıca yeni iş parçacığı için stdin, out ve err tanımlamak için):

try:
    pid = os.fork()
except OSError, e:
    ## some debug output
    sys.exit(1)
if pid == 0:
    ## eventually use os.putenv(..) to set environment variables
    ## os.execv strips of args[0] for the arguments
    os.execv(args[0], args)

2
os.fork()gerçekten kullanışlıdır, ancak yalnızca * nix'te mevcut olmanın dikkate değer bir dezavantajı vardır.
Evan Fosmark

Os.fork ile ilgili tek sorun, win32'ye özgü olmasıdır.
jkp

Bu yaklaşım hakkında daha fazla bilgi: Python yolu ile bir daemon oluşturma
Amir Ali Akbari

Şunlara da benzer efektlere ulaşabilirsiniz threading: stackoverflow.com/a/53751896/895245 Bunun Windows üzerinde çalışabileceğini düşünüyorum.
Ciro Santilli 法轮功 冠状 病 六四 事件 法轮功

9

Hem çıktıyı yakalayın hem de threading

Bu cevapta belirtildiği gibi , çıktıyı yakalar stdout=ve sonra denerseniz read(), işlem engeller.

Bununla birlikte, buna ihtiyacınız olan durumlar vardır. Örneğin, aralarındaki bir bağlantı noktası üzerinden konuşan iki işlemi başlatmak ve stdout'larını bir günlük dosyasına ve stdout'a kaydetmek istedim .

threadingModül bunları yapmamıza olanak verir.

İlk olarak, bu soruda çıkış yeniden yönlendirme kısmının nasıl tek başına yapılacağına bir göz atın: Python Popen: Aynı anda stdout AND log dosyasına yaz

Sonra:

main.py

#!/usr/bin/env python3

import os
import subprocess
import sys
import threading

def output_reader(proc, file):
    while True:
        byte = proc.stdout.read(1)
        if byte:
            sys.stdout.buffer.write(byte)
            sys.stdout.flush()
            file.buffer.write(byte)
        else:
            break

with subprocess.Popen(['./sleep.py', '0'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) as proc1, \
     subprocess.Popen(['./sleep.py', '10'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) as proc2, \
     open('log1.log', 'w') as file1, \
     open('log2.log', 'w') as file2:
    t1 = threading.Thread(target=output_reader, args=(proc1, file1))
    t2 = threading.Thread(target=output_reader, args=(proc2, file2))
    t1.start()
    t2.start()
    t1.join()
    t2.join()

sleep.py

#!/usr/bin/env python3

import sys
import time

for i in range(4):
    print(i + int(sys.argv[1]))
    sys.stdout.flush()
    time.sleep(0.5)

Koşu sonrası:

./main.py

stdout, her iki satır için 0.5 saniyede bir güncellenir:

0
10
1
11
2
12
3
13

ve her günlük dosyası belirli bir işlem için ilgili günlüğü içerir.

İlham kaynağı: https://eli.thegreenplace.net/2017/interacting-with-a-long-running-child-process-in-python/

Ubuntu 18.04, Python 3.6.7 üzerinde test edilmiştir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.