पायथन में एक धागे के अंदर बुलाए जाने पर sys.exit () बाहर क्यों नहीं निकलता है?


98

यह एक मूर्खतापूर्ण प्रश्न हो सकता है, लेकिन मैं पायथन के बारे में अपनी कुछ धारणाओं का परीक्षण कर रहा हूं और मैं इस उलझन में हूं कि निम्न कोड स्निपेट को थ्रेड में बुलाया जाने पर बाहर नहीं निकलेगा, लेकिन मुख्य धागे में कॉल करने पर बाहर निकल जाएगा।

import sys, time
from threading import Thread

def testexit():
    time.sleep(5)
    sys.exit()
    print "post thread exit"

t = Thread(target = testexit)
t.start()
t.join()
print "pre main exit, post thread exit"
sys.exit()
print "post main exit"

Sys.exit () के लिए डॉक्स बताता है कि कॉल को पायथन से बाहर निकलना चाहिए। मैं इस कार्यक्रम के आउटपुट से देख सकता हूं कि "पोस्ट थ्रेड एग्जिट" कभी भी प्रिंट नहीं किया जाता है, लेकिन थ्रेड कॉल के बाहर निकलने के बाद भी मुख्य धागा चलता रहता है।

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

जवाबों:


71

sys.exit()SystemExitअपवाद को उठाता है, जैसा करता है thread.exit()। तो, जब sys.exit()उस थ्रेड को उस थ्रेड के अंदर उठाया जाता है , तो कॉलिंग के समान प्रभाव पड़ता है thread.exit(), यही कारण है कि केवल थ्रेड बाहर निकलता है।


23

क्या होगा अगर मैं धागे से कार्यक्रम से बाहर निकलना चाहता था?

वर्णित विधि के अलावा डीस्टैन आप कॉल कर सकते हैं os._exit(अंडरस्कोर नोटिस करें)। उपयोग करने से पहले यह सुनिश्चित कर लें कि आप समझते हैं कि यह कोई क्लीनअप (जैसे कॉलिंग __del__या समान) नहीं करता है।


2
क्या यह I / O फ्लश करेगा?
लोरेंजो बेल्ली

1
os._exit (n): "क्लीन एन हैंडलर्स, फ्लशिंग स्टीडियो बफ़र्स, आदि को कॉल किए बिना, स्थिति n के साथ प्रक्रिया से बाहर निकलें।"
टिम रिचर्डसन

ध्यान दें कि जब os._exitशाप के भीतर उपयोग किया जाता है तो कंसोल इसके साथ एक सामान्य स्थिति में रीसेट नहीं होता है। resetइसे ठीक करने के लिए आपको यूनिक्स-शेल में निष्पादित करना होगा।
sjngm

22

क्या होगा अगर मैं थ्रेड से प्रोग्राम से बाहर निकलना चाहता था (ऐसा नहीं जिसे मैं वास्तव में करना चाहता हूं, लेकिन बस इतना मुझे समझ में आता है)?

कम से कम लिनक्स पर आप कर सकते हैं:

os.kill(os.getpid(), signal.SIGINT)

यह SIGINTमुख्य धागे को भेजता है जो एक उठाता है KeyboardInterrupt। उस के साथ आप एक उचित सफाई है। अगर आपको जरूरत हो तो आप सिग्नल को संभाल भी सकते हैं।

BTW: विंडोज पर आप केवल एक SIGTERMसिग्नल भेज सकते हैं, जिसे पायथन से नहीं पकड़ा जा सकता है। उस मामले में आप बस os._exitएक ही प्रभाव के साथ उपयोग कर सकते हैं ।


1
इसके अलावा os._exit
sjngm

12

क्या तथ्य यह है कि "पूर्व मुख्य निकास, पोस्ट थ्रेड निकास" मुद्रित है जो आपको परेशान कर रहा है?

कुछ अन्य भाषाओं (जैसे जावा) के विपरीत जहां एनालॉग sys.exit(में System.exit, जावा के मामले में) वीएम / प्रक्रिया / दुभाषिया को तुरंत बंद करने का कारण बनता है, पायथन का sys.exitसिर्फ एक अपवाद फेंकता है: विशेष रूप से एक SystemExit अपवाद।

यहाँ sys.exit(सिर्फ print sys.exit.__doc__) के लिए डॉक्स हैं :

SystemExit (स्थिति) बढ़ाकर दुभाषिया से बाहर निकलें।
यदि स्थिति छोड़ी गई है या कोई नहीं है, तो यह शून्य (यानी, सफलता) के लिए चूक जाता है।
यदि स्थिति संख्यात्मक है, तो इसका उपयोग सिस्टम निकास स्थिति के रूप में किया जाएगा।
यदि यह एक अन्य प्रकार की वस्तु है, तो इसे मुद्रित किया जाएगा और सिस्टम से
बाहर निकलने की स्थिति एक होगी (यानी, विफलता)।

इसके कुछ परिणाम हैं:

  • एक धागे में यह सिर्फ मौजूदा धागे को मारता है, न कि पूरी प्रक्रिया को (यह मानते हुए कि यह स्टैक के शीर्ष तक जाता है ...)
  • ऑब्जेक्ट डिस्ट्रक्टर्स ( __del__) संभावित रूप से स्टैक फ्रेम के रूप में लगाए जाते हैं जो उन वस्तुओं को संदर्भित करते हैं जो अनजाने हैं
  • अंत में ब्लॉकों को स्टैक अनइंड्स के रूप में निष्पादित किया जाता है
  • आप एक SystemExitअपवाद को पकड़ सकते हैं

आखिरी संभवतः सबसे आश्चर्यजनक है, और अभी तक एक और कारण है कि आपको exceptअपने पायथन कोड में लगभग कभी भी अयोग्य बयान नहीं देना चाहिए ।


11

क्या होगा अगर मैं थ्रेड से प्रोग्राम से बाहर निकलना चाहता था (ऐसा नहीं जिसे मैं वास्तव में करना चाहता हूं, लेकिन बस इतना मुझे समझ में आता है)?

मेरा पसंदीदा तरीका एर्लांग-ईश संदेश गुजर रहा है। थोड़ा अनुकरण, मैं इसे इस तरह से करते हैं:

import sys, time
import threading
import Queue # thread-safe

class CleanExit:
  pass

ipq = Queue.Queue()

def testexit(ipq):
  time.sleep(5)
  ipq.put(CleanExit)
  return

threading.Thread(target=testexit, args=(ipq,)).start()
while True:
  print "Working..."
  time.sleep(1)
  try:
    if ipq.get_nowait() == CleanExit:
      sys.exit()
  except Queue.Empty:
    pass

3
आपको Queueयहां जरूरत नहीं है। बस एक साधारण boolठीक कर देगा। इस चर का क्लासिक नाम है is_activeऔर इसका प्रारंभिक डिफ़ॉल्ट मान है True
एक्यूमेनस

3
हाँ आप सही हैं। Effbot.org/zone/thread-synchronization.htm के अनुसार , boolइस विशेष समस्या के लिए (या कोई अन्य परमाणु ऑपरेशन) पूरी तरह से संशोधित करना होगा। कारण मैं के साथ जाना Queueकि जब थ्रेडेड एजेंटों के साथ काम कर मैंने कई अलग-अलग संकेतों की आवश्यकता होगी, खत्म करने के लिए जाते है ( flush, reconnect, exit, आदि ...) के लगभग तुरंत।
दीस्टन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.