पायथन में पृष्ठभूमि की प्रक्रिया कैसे शुरू करें?


295

मैं एक शेल स्क्रिप्ट को बहुत अधिक पठनीय अजगर संस्करण में पोर्ट करने की कोशिश कर रहा हूं। मूल शेल स्क्रिप्ट पृष्ठभूमि में "और" के साथ कई प्रक्रियाएं (उपयोगिताओं, मॉनिटर आदि) शुरू करती हैं। मैं अजगर में समान प्रभाव कैसे प्राप्त कर सकता हूं? मैं चाहता हूं कि जब अजगर स्क्रिप्ट पूरी हो जाएं तो मैं इन प्रक्रियाओं को नहीं मरूंगा। मुझे यकीन है कि यह किसी तरह एक डेमन की अवधारणा से संबंधित है, लेकिन मुझे यह आसानी से नहीं मिल रहा है।



1
हाय आर्टेम। कृपया दान का उत्तर स्वीकार करें क्योंकि (1) अधिक वोट, (2) subprocess.Popen()2010 के बाद से नया अनुशंसित तरीका है (हम अब 2015 में हैं) और (3) यहां दोहराए गए प्रश्न को पुनर्निर्देशित करने के बारे में भी एक स्वीकृत उत्तर है subprocess.Popen()। चियर्स :-)
ओलिब्रे

1
@olibre वास्तव में इसका उत्तर subprocess.Popen("<command>")उपयुक्त कमांड के नेतृत्व में <कमांड> फ़ाइल के साथ होना चाहिए । बैश और पाइथन लिपियों के साथ मेरे (डेबियन) के लिए एकदम सही काम करता है, जो shellमूल रूप से अपनी मूल प्रक्रिया को पूरा करता है और जीवित रहता है। stdoutमाता-पिता की तुलना में एक ही टर्मिनल पर जाता है। इसलिए यह &एक शेल में बहुत काम करता है जो ओपी का अनुरोध था। लेकिन नरक, सभी प्रश्न बहुत जटिल होते हैं, जबकि थोड़ी सी परीक्षा ने इसे कुछ ही समय में दिखाया;)
flaschbier

पृष्ठभूमि के लिए शायद यह भी देखें stackoverflow.com/a/51950538/874188
tripleee

जवाबों:


84

नोट : यह उत्तर उस समय की तुलना में कम है जब 2009 में पोस्ट किया गया था। subprocessअन्य उत्तरों में दिखाए गए मॉड्यूल का उपयोग अब डॉक्स में करने की सिफारिश की गई है

(ध्यान दें कि उपप्रोसेस मॉड्यूल नई प्रक्रियाओं को पैदा करने और उनके परिणामों को पुनः प्राप्त करने के लिए अधिक शक्तिशाली सुविधाएं प्रदान करता है; उस मॉड्यूल का उपयोग इन कार्यों का उपयोग करने के लिए बेहतर है।)


यदि आप चाहते हैं कि आपकी प्रक्रिया पृष्ठभूमि में शुरू हो तो आप system()उसका उपयोग कर सकते हैं और उसे उसी तरह से कॉल कर सकते हैं जैसे आपकी शेल स्क्रिप्ट ने किया था, या आप spawnइसे कर सकते हैं:

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

(या, वैकल्पिक रूप से, आप कम पोर्टेबल की कोशिश कर सकते हैं os.P_NOWAIT ध्वज की )।

दस्तावेज़ यहाँ देखें ।


8
टिप्पणी: आपको निष्पादन योग्य के लिए पूर्ण पथ निर्दिष्ट करना होगा। यह फ़ंक्शन PATH वैरिएबल का उपयोग नहीं करेगा और जिस वेरिएंट का उपयोग करता है वह विंडोज के तहत उपलब्ध नहीं है।
सोरिन

36
सीधे मेरे लिए अजगर दुर्घटनाग्रस्त हो गया।
पाब्लो

29
os.P_DETACH को os.P_NOWAIT से बदल दिया गया है।
खुद

7
क्या लोग subprocessहमें सुझाव दे रहे हैं कि हम कैसे एक प्रक्रिया को अलग कर सकते हैं subprocess?
21

3
मैं एक पृष्ठभूमि प्रक्रिया खोजने के लिए पायथन स्क्रिप्ट (कहो संलग्नक) का उपयोग कैसे कर सकता हूं और इसके IO को पुनर्निर्देशित कर सकता हूं ताकि संलग्नक पृष्ठभूमि में some_long_running_prog से पढ़ / लिख सकें?
raof01

376

जबकि jkp का समाधान काम करता है, चीजों को करने का नया तरीका (और जिस तरह से प्रलेखन अनुशंसा करता है) का उपयोग करना हैsubprocess मॉड्यूल है। साधारण कमांड के लिए इसके समकक्ष, लेकिन यदि आप कुछ जटिल करना चाहते हैं तो यह अधिक विकल्प प्रदान करता है।

आपके मामले के लिए उदाहरण:

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

यह rm -r some.fileबैकग्राउंड में चलेगा । ध्यान दें कि .communicate()ऑब्जेक्ट से कॉलिंग Popenपूरी होने तक बंद हो जाएगी, इसलिए ऐसा न करें कि यदि आप चाहते हैं कि यह पृष्ठभूमि में चला जाए:

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

दस्तावेज़ यहाँ देखें

इसके अलावा, स्पष्टीकरण का एक बिंदु: "पृष्ठभूमि" जैसा कि आप इसे यहां उपयोग करते हैं, विशुद्ध रूप से एक शेल अवधारणा है; तकनीकी रूप से, आपके कहने का मतलब यह है कि आप एक प्रक्रिया को बिना अवरुद्ध किए छोड़ देना चाहते हैं जबकि आप इसे पूरा होने का इंतजार करते हैं। हालाँकि, मैंने शेल-बैकग्राउंड जैसे व्यवहार को संदर्भित करने के लिए "बैकग्राउंड" का उपयोग किया है।


7
@Dan: पृष्ठभूमि में चलने पर मैं इस प्रक्रिया को कैसे मार सकता हूँ? मैं इसे थोड़ी देर के लिए चलाना चाहता हूं (यह एक डेमन है जिसे मैं इंटरैक्ट करता हूं) और जब मैं इसके साथ होता हूं तो इसे मार देता हूं। डॉक्स सहायक नहीं हैं ...
जुआन

1
@ लेकिन क्या मुझे उसके लिए पीआईडी ​​जानने की जरूरत नहीं है? गतिविधि मॉनिटर / टास्क मैनेजर एक विकल्प नहीं है (प्रोग्रामेटिक रूप से होने की आवश्यकता है)।
जुआन

5
ठीक है तो आप कैसे प्रक्रिया को पृष्ठभूमि के लिए मजबूर करते हैं जब आपको इसके स्टड को लिखने के लिए पॉपेन () के परिणाम की आवश्यकता होती है?
माइकल

2
@JFSebastian: मैंने इसकी व्याख्या की "मैं एक स्वतंत्र प्रक्रिया कैसे बना सकता हूं जो वर्तमान कार्यक्रम के निष्पादन को रोकती नहीं है"। आप यह कैसे सुझाएंगे कि मैं इसे और अधिक स्पष्ट करने के लिए संपादित करूं।
दान

1
@ दान: सही उत्तर है: Popen()मुख्य धागे को अवरुद्ध करने से बचने के लिए उपयोग करें और यदि आपको एक डेमॉन की आवश्यकता है, तो यह समझने के लिए python-daemonपैकेज को देखें कि एक अच्छी तरह से परिभाषित डेमॉन को कैसे व्यवहार करना चाहिए। आपका जवाब ठीक है अगर आप सबप्रोसेस डॉक्स के लिंक को छोड़कर "बट वरी बी" के साथ शुरू होने वाली सभी चीजों को हटा दें।
jfs

47

आप शायद "पायथन में एक बाहरी कमांड को कैसे कॉल करें" का जवाब चाहते हैं ।

सबसे सरल दृष्टिकोण os.systemसमारोह का उपयोग करना है, जैसे:

import os
os.system("some_command &")

मूल रूप से, जो भी आप systemफ़ंक्शन में जाते हैं, उसे उसी तरह निष्पादित किया जाएगा जैसे कि आप इसे किसी स्क्रिप्ट में शेल में पास करते हैं।


10
IMHO, अजगर लिपियों को आमतौर पर क्रॉस-प्लेटफ़ॉर्म लिखा जाता है और यदि कोई सरल क्रॉस-प्लेटफ़ॉर्म समाधान मौजूद है, तो इसके साथ रहना बेहतर है। कभी नहीं पता है कि आपको भविष्य में किसी अन्य प्लेटफॉर्म के साथ काम करना होगा :) या यदि कोई अन्य व्यक्ति आपकी स्क्रिप्ट को अपने प्लेटफ़ॉर्म पर स्थानांतरित करना चाहेगा।
d9k

7
यह कमांड सिंक्रोनस है (अर्थात यह हमेशा शुरू की गई प्रक्रिया के समापन का इंतजार करता है)।
tav

@ d9k os.system पोर्टेबल नहीं है?
ल्यूसिड_ड्रीमर

1
@ d9k पृष्ठभूमि में कुछ चलाने का विकल्प नहीं है जो आपको पहले से ही पॉज़िक्स-भूमि में ला रहा है? आप विंडोज पर क्या करेंगे? सेवा के रूप में चलाएं?
ल्यूसिड_ड्रीमर

यदि मुझे किसी विशिष्ट फ़ोल्डर से कमांड चलाने की आवश्यकता है तो मैं इसका उपयोग कैसे कर सकता हूं?
mrRobot

29

मुझे यह यहाँ मिला :

विंडोज़ पर (xp जीतने के लिए), मूल प्रक्रिया तब तक खत्म नहीं होगी जब तक longtask.pyउसका काम खत्म नहीं हो जाता । यह वह नहीं है जो आप सीजीआई-स्क्रिप्ट में चाहते हैं। समस्या पाइथन के लिए विशिष्ट नहीं है, PHP समुदाय में समस्याएं समान हैं।

समाधान एपीआई में अंतर्निहित समारोह में DETACHED_PROCESS प्रक्रिया निर्माण ध्वज को पारित करना CreateProcessहै। यदि आपने pywin32 स्थापित किया है, तो आप ध्वज को win32process मॉड्यूल से आयात कर सकते हैं, अन्यथा आपको इसे स्वयं परिभाषित करना चाहिए:

DETACHED_PROCESS = 0x00000008

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

6
प्रक्रिया आईडी को कैसे बनाए रखा जाए, यह दिखाने के लिए +1। और अगर किसी को प्रक्रिया आईडी के साथ बाद में कार्यक्रम को मारना है: stackoverflow.com/questions/17856928/…
iChux

1
यह केवल विंडोज लगता है
ऑड्रियस मेसकॉस्कस

24

पैरामीटर के subprocess.Popen()साथ उपयोग करें close_fds=True, जो स्पॉन्ड सबप्रोसेस को पायथन प्रक्रिया से खुद को अलग करने की अनुमति देगा और पायथन के बाहर निकलने के बाद भी जारी रहेगा।

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
खिड़कियों में, यह अलग नहीं करता है, लेकिन
सृजनफ्लैग

3
यह समाधान लिनक्स पर ज़ोंबी के रूप में एक उपप्रकार छोड़ देता है।
टाइटनफाइटर

@TitanFighter इस सेट से बचा जा सकता है SIGCHLD SIG_IGN: stackoverflow.com/questions/16807603/…
sailfish009

धन्यवाद @Jimmy आपका जवाब मेरे लिए केवल समाधान काम करता है।
सेलफिश009

12

आप शायद अलग-अलग थ्रेड (एक इंटरेक्टिव सत्र खोलकर और मदद (ओएस) जारी करके) के लिए ओएस मॉड्यूल की जांच शुरू करना चाहते हैं। प्रासंगिक कार्य कांटे और निष्पादन वाले किसी भी हैं। आपको कैसे शुरू करने के बारे में एक विचार देने के लिए, एक फ़ंक्शन में ऐसा कुछ डालें जो कांटा करता है (फ़ंक्शन को एक सूची या टुपल 'args' को एक तर्क के रूप में लेने की ज़रूरत है जिसमें प्रोग्राम का नाम और इसके पैरामीटर शामिल हैं; आप भी चाहते हो सकते हैं; स्टड को परिभाषित करने के लिए, नए धागे के लिए और बाहर):

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()वास्तव में उपयोगी है, लेकिन यह केवल * निक्स पर उपलब्ध होने का एक नकारात्मक पहलू है।
इवान फॉसमार्क

Os.fork के साथ एकमात्र समस्या यह है कि यह win32 विशिष्ट है।
jkp

इस दृष्टिकोण के बारे में अधिक जानकारी: एक डेमॉन द पाइथन तरीका बनाना
अमीर अली अकबरी

आप भी इसी तरह के प्रभाव के साथ पहुँच सकते हैं threading: stackoverflow.com/a/53751896/895245 मुझे लगता है कि विंडोज पर काम हो सकता है।
सिरो सेंटिल्ली 郝海东 i iro i

9

दोनों आउटपुट को कैप्चर करते हैं और बैकग्राउंड पर रन करते हैं threading

जैसा कि इस उत्तर में बताया गया है , यदि आप आउटपुट को कैप्चर करते हैं stdout=और फिर करने की कोशिश करते हैं read(), तो प्रक्रिया ब्लॉक हो जाती है।

हालांकि, ऐसे मामले हैं जहां आपको इसकी आवश्यकता है। उदाहरण के लिए, मैं उन दो प्रक्रियाओं को लॉन्च करना चाहता था जो उन दोनों के बीच एक बंदरगाह पर बात करती हैं , और एक लॉग फ़ाइल और stdout में उनके स्टडआउट को बचाती हैं।

threadingमॉड्यूल हमें ऐसा करने की अनुमति देता है।

सबसे पहले, इस सवाल में अकेले आउटपुट पुनर्निर्देशन कैसे करना है पर एक नज़र है: पायथन पॉपेन: एक साथ स्टडआउट और लॉग फ़ाइल लिखें

फिर:

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)

चलने के बाद:

./main.py

Stdout को शामिल करने के लिए हर दो लाइनों के लिए हर 0.5 सेकंड में अपडेट किया जाता है:

0
10
1
11
2
12
3
13

और प्रत्येक लॉग फ़ाइल में किसी दिए गए प्रक्रिया के लिए संबंधित लॉग होता है।

से प्रेरित: https://eli.thegreenplace.net/2017/interacting-with-a-long-running-child-process-in-python/

उबंटू 18.04, पायथन 3.6.7 पर परीक्षण किया गया।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.