Hoe start ik een achtergrondproces in Python?

Ik probeer een shellscript over te zetten naar de veel beter leesbare pythonversie. Het originele shellscript start verschillende processen (hulpprogramma’s, monitors, enz.) op de achtergrond met “&”. Hoe kan ik hetzelfde effect bereiken in python? Ik zou willen dat deze processen niet doodgaan als de Python-scripts zijn voltooid. Ik weet zeker dat het op de een of andere manier gerelateerd is aan het concept van een daemon, maar ik kon niet vinden hoe ik dit gemakkelijk kon doen.


Antwoord 1, autoriteit 100%

Hoewel de oplossing van jkp‘s oplossing werkt, is de nieuwere manier om dingen te doen (en de manier waarop de documentatie aanbeveelt) is om de module subprocesste gebruiken. Voor eenvoudige commando’s is het equivalent, maar het biedt meer opties als je iets ingewikkelds wilt doen.

Voorbeeld voor uw geval:

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

Hiermee wordt rm -r some.fileop de achtergrond uitgevoerd. Merk op dat het aanroepen van .communicate()op het object geretourneerd door Popenblokkeert totdat het is voltooid, dus doe dat niet als u wilt dat het op de achtergrond wordt uitgevoerd:

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

Bekijk de documentatie hier.

Ook een punt van verduidelijking: “Achtergrond” zoals je het hier gebruikt is puur een shell-concept; technisch gezien bedoel je dat je een proces wilt starten zonder te blokkeren terwijl je wacht tot het is voltooid. Ik heb hier echter “achtergrond” gebruikt om te verwijzen naar shell-background-achtig gedrag.


Antwoord 2, autoriteit 22%

Opmerking: dit antwoord is minder actueel dan toen het in 2009 werd gepost. Het wordt nu aanbevolen om de subprocess-module te gebruiken die in andere antwoorden wordt weergegeven in de documenten

(Merk op dat de subprocesmodule krachtigere faciliteiten biedt voor het spawnen van nieuwe processen en het ophalen van hun resultaten; het gebruik van die module heeft de voorkeur boven het gebruik van deze functies.)


Als u wilt dat uw proces op de achtergrond start, kunt u ofwel system()gebruiken en het op dezelfde manier aanroepen als uw shellscript, of u kunt spawnhet:

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

(of u kunt ook de minder draagbare os.P_NOWAIT-vlag proberen).

Bekijk de documentatie hier.


Antwoord 3, autoriteit 12%

U wilt waarschijnlijk het antwoord op “Hoe u een externe opdracht in Python”.

De eenvoudigste benadering is om de functie os.systemte gebruiken, bijvoorbeeld:

import os
os.system("some_command &")

In principe wordt alles wat u doorgeeft aan de functie systemop dezelfde manier uitgevoerd alsof u het in een script aan de shell had doorgegeven.


Antwoord 4, autoriteit 8%

Ik heb dit hiergevonden:

In Windows (win xp) zal het bovenliggende proces niet eindigen totdat de longtask.pyzijn werk heeft voltooid. Het is niet wat je wilt in CGI-script. Het probleem is niet specifiek voor Python, in de PHP-gemeenschap zijn de problemen hetzelfde.

De oplossing is om DETACHED_PROCESSProces Creation Flagnaar de onderliggende CreateProcessfunctie in win API. Als je toevallig pywin32 hebt geïnstalleerd, kun je de vlag importeren uit de win32process-module, anders moet je deze zelf definiëren:

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

Antwoord 5, autoriteit 7%

Gebruik subprocess.Popen()met de parameter close_fds=True, waardoor het voortgebrachte subproces kan worden losgekoppeld van het Python-proces zelf en zelfs na Python kan blijven draaien uitgangen.

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'

Antwoord 6, autoriteit 3%

Zowel uitvoer vastleggen als op de achtergrond draaien met threading

Zoals op dit antwoordvermeld, als u de uitvoer vastlegt met stdout=en vervolgens probeer read(), dan blokkeert het proces.

Er zijn echter gevallen waarin u dit nodig heeft. Ik wilde bijvoorbeeld twee processen starten die praten over een poort tussen hen, en sla hun stdout op in een logbestand en stdout.

Met de threading-modulekunnen we dat.

Bekijk eerst hoe u het uitvoeromleidingsgedeelte alleen in deze vraag kunt doen: Python Popen: schrijf tegelijkertijd naar stdout EN logbestand

Dan:

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)

Na het hardlopen:

./main.py

stdout wordt elke 0,5 seconde bijgewerkt voor elke twee regels die het volgende bevatten:

0
10
1
11
2
12
3
13

en elk logbestand bevat het respectievelijke logbestand voor een bepaald proces.

Geïnspireerd door: https: //eli.thegreenplace.net/2017/interacting-with-a-long-running-child-process-in-python/

Getest op Ubuntu 18.04, Python 3.6.7.


Antwoord 7, autoriteit 3%

U wilt waarschijnlijk beginnen met het onderzoeken van de os-module om verschillende threads te forken (door een interactieve sessie te openen en help(os) uit te geven). De relevante functies zijn fork en een van de exec-functies. Om je een idee te geven hoe je moet beginnen, plaats je zoiets in een functie die de fork uitvoert (de functie moet een lijst of tuple ‘args’ als argument hebben die de naam van het programma en zijn parameters bevat; misschien wil je ook om stdin, out en err voor de nieuwe thread te definiëren):

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)

Antwoord 8

U kunt gebruiken

import os
pid = os.fork()
if pid == 0:
    Continue to other code ...

Hierdoor wordt het python-proces op de achtergrond uitgevoerd.

Other episodes