जवाबों:
यह आमतौर पर पायथन और किसी भी भाषा में अचानक एक धागे को मारने के लिए एक बुरा पैटर्न है। निम्नलिखित मामलों के बारे में सोचो:
इसे संभालने का अच्छा तरीका है अगर आप इसे बर्दाश्त कर सकते हैं (यदि आप अपने स्वयं के धागे का प्रबंधन कर रहे हैं) के पास एक एक्जिट_रेक्वेस्ट झंडा है जिसे प्रत्येक थ्रेड नियमित अंतराल पर जांचता है कि क्या यह बाहर निकलने का समय है।
उदाहरण के लिए:
import threading
class StoppableThread(threading.Thread):
"""Thread class with a stop() method. The thread itself has to check
regularly for the stopped() condition."""
def __init__(self, *args, **kwargs):
super(StoppableThread, self).__init__(*args, **kwargs)
self._stop_event = threading.Event()
def stop(self):
self._stop_event.set()
def stopped(self):
return self._stop_event.is_set()
इस कोड में, आपको stop()
थ्रेड पर कॉल करना चाहिए जब आप इसे बाहर निकलना चाहते हैं, और थ्रेड के ठीक से उपयोग करने के लिए प्रतीक्षा करें join()
। धागे को नियमित अंतराल पर स्टॉप फ्लैग की जांच करनी चाहिए।
हालांकि ऐसे मामले हैं जब आपको वास्तव में एक धागे को मारने की आवश्यकता होती है। एक उदाहरण है जब आप एक बाहरी पुस्तकालय लपेट रहे हैं जो लंबी कॉल के लिए व्यस्त है और आप इसे बाधित करना चाहते हैं।
निम्नलिखित कोड पायथन धागे में एक अपवाद को बढ़ाने के लिए (कुछ प्रतिबंधों के साथ) अनुमति देता है:
def _async_raise(tid, exctype):
'''Raises an exception in the threads with id tid'''
if not inspect.isclass(exctype):
raise TypeError("Only types can be raised (not instances)")
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(ctypes.c_long(tid),
ctypes.py_object(exctype))
if res == 0:
raise ValueError("invalid thread id")
elif res != 1:
# "if it returns a number greater than one, you're in trouble,
# and you should call it again with exc=NULL to revert the effect"
ctypes.pythonapi.PyThreadState_SetAsyncExc(ctypes.c_long(tid), None)
raise SystemError("PyThreadState_SetAsyncExc failed")
class ThreadWithExc(threading.Thread):
'''A thread class that supports raising exception in the thread from
another thread.
'''
def _get_my_tid(self):
"""determines this (self's) thread id
CAREFUL : this function is executed in the context of the caller
thread, to get the identity of the thread represented by this
instance.
"""
if not self.isAlive():
raise threading.ThreadError("the thread is not active")
# do we have it cached?
if hasattr(self, "_thread_id"):
return self._thread_id
# no, look for it in the _active dict
for tid, tobj in threading._active.items():
if tobj is self:
self._thread_id = tid
return tid
# TODO: in python 2.6, there's a simpler way to do : self.ident
raise AssertionError("could not determine the thread's id")
def raiseExc(self, exctype):
"""Raises the given exception type in the context of this thread.
If the thread is busy in a system call (time.sleep(),
socket.accept(), ...), the exception is simply ignored.
If you are sure that your exception should terminate the thread,
one way to ensure that it works is:
t = ThreadWithExc( ... )
...
t.raiseExc( SomeException )
while t.isAlive():
time.sleep( 0.1 )
t.raiseExc( SomeException )
If the exception is to be caught by the thread, you need a way to
check that your thread has caught it.
CAREFUL : this function is executed in the context of the
caller thread, to raise an excpetion in the context of the
thread represented by this instance.
"""
_async_raise( self._get_my_tid(), exctype )
( टोमर फिलिबा द्वारा किलरेबल थ्रेड्स के आधार पर । वापसी मूल्य के बारे में उद्धरण पायथन केPyThreadState_SetAsyncExc
एक पुराने संस्करण से प्रतीत होता है ।)
जैसा कि प्रलेखन में उल्लेख किया गया है, यह एक जादू की गोली नहीं है क्योंकि यदि धागा पायथन दुभाषिया के बाहर व्यस्त है, तो यह रुकावट को नहीं पकड़ेगा।
इस कोड का एक अच्छा उपयोग पैटर्न धागा को एक विशिष्ट अपवाद को पकड़ना और सफाई करना है। इस तरह, आप एक कार्य को बाधित कर सकते हैं और अभी भी उचित सफाई कर सकते हैं।
SO_REUSEADDR
से बचने के लिए सॉकेट विकल्प का उपयोग कर सकते हैं Address already in use
।
None
के बजाय 0
के लिए res != 1
मामला है, और मैं फोन करने के लिए किया था ctypes.c_long(tid)
और पारित करने के लिए कि किसी भी ctypes टीआईडी सीधे के बजाय कार्य करते हैं।
ऐसा करने के लिए कोई आधिकारिक एपीआई नहीं है, नहीं।
आपको धागा को मारने के लिए प्लेटफ़ॉर्म एपीआई का उपयोग करने की आवश्यकता है, जैसे pthread_kill, या TerminateThread। आप ऐसे API का उपयोग कर सकते हैं जैसे कि pythonwin के माध्यम से, या ctypes के माध्यम से।
ध्यान दें कि यह स्वाभाविक रूप से असुरक्षित है। यह संभवतया अचिन्त्य कचरा (स्टैक फ्रेम के स्थानीय चर से जो कचरा बन जाता है) को जन्म देगा, और डेडलॉक हो सकता है, यदि धागे को मारा जा रहा है, तो इसे मारने पर बिंदु पर जीआईएल होगा।
A multiprocessing.Process
कर सकते हैंp.terminate()
उन मामलों में जहां मैं एक धागे को मारना चाहता हूं, लेकिन झंडे / ताले / सिग्नल / सेमाफोरस / घटनाओं / जो कुछ भी उपयोग करना नहीं चाहता हूं, मैं थ्रेड्स को पूर्ण विकसित प्रक्रियाओं को बढ़ावा देता हूं। कोड है कि सिर्फ कुछ धागे का उपयोग करता है के लिए ओवरहेड कि बुरा नहीं है।
उदाहरण के लिए, यह हेल्पर "थ्रेड्स" को आसानी से समाप्त करने के काम आता है, जो ब्लॉकिंग I / O को निष्पादित करता है
रूपांतरण तुच्छ है: संबंधित कोड में सभी threading.Thread
को प्रतिस्थापित करें multiprocessing.Process
और सभी के queue.Queue
साथ multiprocessing.Queue
आवश्यक कॉल जोड़ेंp.terminate()
अपनी मूल प्रक्रिया जो अपने बच्चे को मारना चाहता हैp
के लिए पायथन प्रलेखनmultiprocessing
देखें ।
multiprocessing
अच्छा है, लेकिन ध्यान रखें कि तर्कों को नई प्रक्रिया के लिए चुना जाता है। इसलिए यदि कोई एक तर्क कुछ न करने योग्य (जैसे logging.log
) है तो इसका उपयोग करना एक अच्छा विचार नहीं हो सकता है multiprocessing
।
multiprocessing
तर्क विंडोज पर नई प्रक्रिया के लिए ले जाया जाता है, लेकिन लिनक्स उन्हें कॉपी करने के लिए फोर्किंग का उपयोग करता है (पायथन 3.7, अन्य संस्करणों को अनिश्चित करें)। तो आप उस कोड को समाप्त कर देंगे जो लिनक्स पर काम करता है लेकिन विंडोज पर अचार की त्रुटियों को बढ़ाता है।
multiprocessing
लॉगिंग के साथ मुश्किल काम है। उपयोग करने की आवश्यकता है QueueHandler
( इस ट्यूटोरियल को देखें )। मैंने इसे कठिन तरीके से सीखा।
यदि आप पूरे कार्यक्रम को समाप्त करने की कोशिश कर रहे हैं, तो आप थ्रेड को "डेमॉन" के रूप में सेट कर सकते हैं। देखें Thread.daemon
जैसा कि दूसरों ने उल्लेख किया है, मानदंड स्टॉप फ्लैग सेट करना है। कुछ हल्का (थ्रेड का कोई उपवर्ग नहीं, कोई वैश्विक चर नहीं) के लिए, एक लैम्ब्डा कॉलबैक एक विकल्प है। (कोष्ठकों पर ध्यान दें if stop()
।)
import threading
import time
def do_work(id, stop):
print("I am thread", id)
while True:
print("I am thread {} doing something".format(id))
if stop():
print(" Exiting loop.")
break
print("Thread {}, signing off".format(id))
def main():
stop_threads = False
workers = []
for id in range(0,3):
tmp = threading.Thread(target=do_work, args=(id, lambda: stop_threads))
workers.append(tmp)
tmp.start()
time.sleep(3)
print('main: done sleeping; time to stop the threads.')
stop_threads = True
for worker in workers:
worker.join()
print('Finis.')
if __name__ == '__main__':
main()
print()
एक pr()
फ़ंक्शन के साथ प्रतिस्थापित करना जो हमेशा फ्लश करता है ( sys.stdout.flush()
) शेल आउटपुट की शुद्धता में सुधार कर सकता है।
(केवल विंडोज / एक्लिप्स / पायथन 3.3 पर परीक्षण किया गया)
pr()
कार्य क्या है ?
यह पर आधारित है थ्रेड 2 - हत्या करने योग्य धागे (पायथन नुस्खा)
आपको PyThreadState_SetasyncExc () कॉल करने की आवश्यकता है, जो केवल ctypes के माध्यम से उपलब्ध है।
यह केवल पायथन 2.7.3 पर परीक्षण किया गया है, लेकिन यह हाल के 2.x रिलीज के साथ काम करने की संभावना है।
import ctypes
def terminate_thread(thread):
"""Terminates a python thread from another thread.
:param thread: a threading.Thread instance
"""
if not thread.isAlive():
return
exc = ctypes.py_object(SystemExit)
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(
ctypes.c_long(thread.ident), exc)
if res == 0:
raise ValueError("nonexistent thread id")
elif res > 1:
# """if it returns a number greater than one, you're in trouble,
# and you should call it again with exc=NULL to revert the effect"""
ctypes.pythonapi.PyThreadState_SetAsyncExc(thread.ident, None)
raise SystemError("PyThreadState_SetAsyncExc failed")
KeyboardInterrupt
ताकि उन्हें साफ करने का मौका मिले। यदि वे उसके बाद भी लटक रहे हैं, तो SystemExit
उचित है, या बस एक टर्मिनल से प्रक्रिया को मार डालो।
pthread_cleanup_push()/_pop()
, इसके विवेकपूर्ण उपयोग से , इसे सही ढंग से लागू करने के लिए बहुत काम होगा और यह दुभाषिया को धीमा कर देगा।
आपको कभी भी किसी के साथ सहयोग के बिना जबरन एक धागा नहीं मारना चाहिए।
एक धागा को मारना किसी भी गारंटी को हटा देता है जो कोशिश करता है / अंत में सेट होता है ताकि आप ताले को बंद कर सकें, फाइलें खुली रहें, आदि।
केवल एक बार आप यह तर्क दे सकते हैं कि थ्रेड्स को जबरन मारना एक अच्छा विचार है, किसी प्रोग्राम को तेजी से मारना है, लेकिन कभी भी सिंगल थ्रेड्स को मारना नहीं है।
अजगर में, आप सीधे एक धागा नहीं मार सकते हैं।
यदि आपको वास्तव में थ्रेड पैकेज का उपयोग करने के बजाय थ्रेड (!) होने की आवश्यकता नहीं है, तो मल्टीप्रोसेसिंग पैकेज का उपयोग करना है । यहां, एक प्रक्रिया को मारने के लिए, आप बस विधि को कॉल कर सकते हैं:
yourProcess.terminate() # kill the process!
अजगर आपकी प्रक्रिया को मार देगा (यूनिक्स पर SIGTERM सिग्नल के माध्यम से, जबकि विंडोज के माध्यम से TerminateProcess()
कॉल के )। एक कतार या एक पाइप का उपयोग करते समय इसका उपयोग करने के लिए ध्यान दें! (यह कतार / पाइप में डेटा को दूषित कर सकता है)
ध्यान दें कि multiprocessing.Event
और multiprocessing.Semaphore
काम बिल्कुल उसी तरह से threading.Event
औरthreading.Semaphore
क्रमशः। वास्तव में, पहले वाले अक्षांशों के क्लोन हैं।
यदि आपको वास्तव में थ्रेड का उपयोग करने की आवश्यकता है, तो इसे सीधे मारने का कोई तरीका नहीं है। हालांकि, आप क्या कर सकते हैं, "डेमन थ्रेड" का उपयोग करना है । वास्तव में, पायथन में, एक धागे को डेमन के रूप में चिह्नित किया जा सकता है :
yourThread.daemon = True # set the Thread as a "daemon thread"
मुख्य कार्यक्रम से बाहर निकल जाएगा जब कोई जीवित गैर-डेमॉन धागे नहीं बचे हैं। दूसरे शब्दों में, जब आपका मुख्य धागा (जो कि, निश्चित रूप से, एक गैर-डेमॉन थ्रेड) है, तो अपने संचालन को समाप्त कर देगा, प्रोग्राम तब भी बाहर निकल जाएगा, जब अभी भी कुछ डेमन थ्रेड काम कर रहे हों।
ध्यान दें कि विधि कहा जाने daemon
से पहले थ्रेड सेट करना आवश्यक start()
है!
बेशक आप कर सकते हैं, और चाहिए, के daemon
साथ भी उपयोग करें multiprocessing
। यहां, जब मुख्य प्रक्रिया से बाहर निकलता है, तो यह अपने सभी शैतानी बच्चे प्रक्रियाओं को समाप्त करने का प्रयास करता है।
अंत में, कृपया ध्यान दें कि sys.exit()
और os.kill()
विकल्प नहीं हैं।
आप थ्रेड में ट्रेस स्थापित करके एक थ्रेड को मार सकते हैं जो थ्रेड से बाहर निकल जाएगा। एक संभावित कार्यान्वयन के लिए संलग्न लिंक देखें।
यदि आप स्पष्ट time.sleep()
रूप से अपने धागे के हिस्से के रूप में कॉल कर रहे हैं (कुछ बाहरी सेवा को मतदान कहते हैं), तो फ़िलिप की विधि में सुधार event
'एस में टाइमआउट का उपयोग करना है।wait()
जहाँ भी आप विधिsleep()
उदाहरण के लिए:
import threading
class KillableThread(threading.Thread):
def __init__(self, sleep_interval=1):
super().__init__()
self._kill = threading.Event()
self._interval = sleep_interval
def run(self):
while True:
print("Do Something")
# If no kill signal is set, sleep for the interval,
# If kill signal comes in while sleeping, immediately
# wake up and handle
is_killed = self._kill.wait(self._interval)
if is_killed:
break
print("Killing Thread")
def kill(self):
self._kill.set()
फिर इसे चलाने के लिए
t = KillableThread(sleep_interval=5)
t.start()
# Every 5 seconds it prints:
#: Do Something
t.kill()
#: Killing Thread
आईएनजी के wait()
बजाय उपयोग करने sleep()
और नियमित रूप से घटना की जांच करने का लाभ यह है कि आप नींद के लंबे अंतराल में प्रोग्राम कर सकते हैं, थ्रेड लगभग तुरंत बंद हो जाता है (जब आप अन्यथा sleep()
आईएनजी होंगे) और मेरी राय में, बाहर निकलने से निपटने के लिए कोड काफी सरल है ।
यदि आप किसी धागे को नहीं मारते हैं तो बेहतर है। एक तरीका यह हो सकता है कि आप थ्रेड के चक्र में एक "कोशिश" ब्लॉक शुरू करें और एक अपवाद फेंकें जब आप थ्रेड को रोकना चाहते हैं (उदाहरण के लिए ब्रेक / रिटर्न / ... जो आपके / / / ... के लिए आपके स्टॉप को रोकता है)। मैंने अपने ऐप पर इसका उपयोग किया है और यह काम करता है ...
Thread.stop
निम्न उदाहरण कोड में दिखाए गए तरीके से इसे लागू करना निश्चित रूप से संभव है :
import sys
import threading
import time
class StopThread(StopIteration):
pass
threading.SystemExit = SystemExit, StopThread
class Thread2(threading.Thread):
def stop(self):
self.__stop = True
def _bootstrap(self):
if threading._trace_hook is not None:
raise ValueError('Cannot run thread with tracing!')
self.__stop = False
sys.settrace(self.__trace)
super()._bootstrap()
def __trace(self, frame, event, arg):
if self.__stop:
raise StopThread()
return self.__trace
class Thread3(threading.Thread):
def _bootstrap(self, stop_thread=False):
def stop():
nonlocal stop_thread
stop_thread = True
self.stop = stop
def tracer(*_):
if stop_thread:
raise StopThread()
return tracer
sys.settrace(tracer)
super()._bootstrap()
###############################################################################
def main():
test1 = Thread2(target=printer)
test1.start()
time.sleep(1)
test1.stop()
test1.join()
test2 = Thread2(target=speed_test)
test2.start()
time.sleep(1)
test2.stop()
test2.join()
test3 = Thread3(target=speed_test)
test3.start()
time.sleep(1)
test3.stop()
test3.join()
def printer():
while True:
print(time.time() % 1)
time.sleep(0.1)
def speed_test(count=0):
try:
while True:
count += 1
except StopThread:
print('Count =', count)
if __name__ == '__main__':
main()
Thread3
वर्ग लगभग 33% से अधिक तेजी से कोड को चलाने के लिए प्रकट होता है Thread2
वर्ग।
self.__stop
थ्रेड में सेट होने के लिए चेकों को इंजेक्ट करने का एक चतुर तरीका है । ध्यान दें कि यहां अन्य समाधानों में से अधिकांश की तरह, यह वास्तव में एक अवरुद्ध कॉल को बाधित नहीं करेगा, क्योंकि ट्रेस फ़ंक्शन केवल तभी कॉल करता है जब एक नया स्थानीय क्षेत्र दर्ज किया जाता है। यह भी ध्यान देने योग्य है कि sys.settrace
वास्तव में डिबगर्स, प्रोफाइल इत्यादि को लागू करने के लिए है और जैसे कि सीपीथॉन का कार्यान्वयन विवरण माना जाता है, और अन्य पायथन कार्यान्वयन में मौजूद होने की गारंटी नहीं है।
Thread2
वर्ग के साथ सबसे बड़ी समस्याओं में से एक यह है कि यह लगभग दस गुना धीमा कोड चलाता है। कुछ लोगों को अभी भी यह स्वीकार्य लग सकता है।
from ctypes import *
pthread = cdll.LoadLibrary("libpthread-2.15.so")
pthread.pthread_cancel(c_ulong(t.ident))
टी आपका हैThread
वस्तु है।
अजगर स्रोत पढ़ें ( Modules/threadmodule.c
और Python/thread_pthread.h
) आप देख सकते हैं Thread.ident
एक pthread_t
प्रकार है, इसलिए आप pthread
अजगर के उपयोग में कुछ भी कर सकते हैं libpthread
।
थ्रेड को मारने के लिए निम्नलिखित वर्कअराउंड का उपयोग किया जा सकता है:
kill_threads = False
def doSomething():
global kill_threads
while True:
if kill_threads:
thread.exit()
......
......
thread.start_new_thread(doSomething, ())
इसका उपयोग थ्रेड को समाप्त करने के लिए भी किया जा सकता है, जिसका कोड मुख्य थ्रेड से दूसरे मॉड्यूल में लिखा गया है। हम उस मॉड्यूल में एक वैश्विक चर घोषित कर सकते हैं और इसका उपयोग उस मॉड्यूल में थ्रेडेड / एस को समाप्त करने के लिए कर सकते हैं।
मैं आमतौर पर प्रोग्राम से बाहर निकलने के सभी थ्रेड्स को समाप्त करने के लिए इसका उपयोग करता हूं। यह धागा / एस को समाप्त करने का सही तरीका नहीं हो सकता है, लेकिन मदद कर सकता है।
मुझे इस खेल में देर हो गई है, लेकिन मैं एक समान प्रश्न के साथ कुश्ती कर रहा हूं और निम्नलिखित दोनों मेरे लिए पूरी तरह से मुद्दे को हल करते हैं और मुझे कुछ बुनियादी धागा राज्य की जाँच करने और सफाई करने की अनुमति देता है जब डेमनीकृत उप-धागा बाहर निकलता है:
import threading
import time
import atexit
def do_work():
i = 0
@atexit.register
def goodbye():
print ("'CLEANLY' kill sub-thread with value: %s [THREAD: %s]" %
(i, threading.currentThread().ident))
while True:
print i
i += 1
time.sleep(1)
t = threading.Thread(target=do_work)
t.daemon = True
t.start()
def after_timeout():
print "KILL MAIN THREAD: %s" % threading.currentThread().ident
raise SystemExit
threading.Timer(2, after_timeout).start()
पैदावार:
0
1
KILL MAIN THREAD: 140013208254208
'CLEANLY' kill sub-thread with value: 2 [THREAD: 140013674317568]
SystemExit
पर उठाना after_timeout
मुख्य थ्रेड के लिए कुछ भी क्यों नहीं करेगा (जो कि पूर्व में इस उदाहरण से बाहर निकलने का इंतजार कर रहा है)?
SystemExit
में केवल दो विशेष गुण हैं: यह एक ट्रेसबैक (जब किसी भी धागे को एक फेंकने से बाहर निकलता है) का उत्पादन नहीं करता है, और यदि एक फेंकने से मुख्य धागा बाहर निकलता है तो बाहर निकलने की स्थिति निर्धारित करता है (जबकि फिर भी अन्य गैर-डीमन थ्रेड्स की प्रतीक्षा कर रहा है) बाहर निकलने के लिए)।
एक बात जो मैं जोड़ना चाहता हूं वह यह है कि यदि आप आधिकारिक दस्तावेज को थ्रेडिंग लेबर पायथन में पढ़ते हैं , तो यह "राक्षसी" धागे के उपयोग से बचने की सिफारिश की जाती है, जब आप थ्रेड को अचानक समाप्त नहीं करना चाहते हैं, तो उस ध्वज के साथ जिसे पाओलो रूवेल्ली ने उल्लेख किया है ।
आधिकारिक दस्तावेज से:
डेमन थ्रेड्स को अचानक बंद कर दिया जाता है। उनके संसाधन (जैसे खुली फाइलें, डेटाबेस लेनदेन, आदि) ठीक से जारी नहीं किए जा सकते हैं। यदि आप चाहते हैं कि आपके धागे सुशोभित रूप से बंद हो जाएं, तो उन्हें गैर-डायमोनिक बनाएं और एक घटना जैसे उपयुक्त सिग्नलिंग तंत्र का उपयोग करें।
मुझे लगता है कि डेमोनिक धागे बनाना आपके आवेदन पर निर्भर करता है, लेकिन सामान्य तौर पर (और मेरी राय में) यह बेहतर है कि उन्हें मारने या उन्हें डायमोनिक बनाने से बचें। मल्टीप्रोसेसिंग में आप is_alive()
प्रक्रिया की स्थिति की जांच करने के लिए और उन्हें समाप्त करने के लिए "समाप्त" का उपयोग कर सकते हैं (साथ ही आप जीआईएल की समस्याओं से बचते हैं)। लेकिन आप और अधिक समस्याएँ पा सकते हैं, कभी-कभी, जब आप अपने कोड को विंडोज में निष्पादित करते हैं।
और हमेशा याद रखें कि यदि आपके पास "जीवित धागे" हैं, तो पायथन दुभाषिया उन्हें इंतजार करने के लिए चला रहा होगा। (इस वजह से डेमोनिक आपकी मदद कर सकता है अगर अचानक कोई फर्क नहीं पड़ता)।
इस उद्देश्य के लिए एक पुस्तकालय बनाया गया है, स्टॉपिट । यद्यपि यहां सूचीबद्ध कुछ समान सावधानीएं अभी भी लागू होती हैं, कम से कम यह पुस्तकालय घोषित लक्ष्य को प्राप्त करने के लिए एक नियमित, दोहराए जाने वाली तकनीक प्रस्तुत करता है।
हालांकि यह पुराना है, यह कुछ के लिए एक उपयोगी समाधान हो सकता है:
एक छोटा मॉड्यूल जो थ्रेडिंग के मॉड्यूल की कार्यक्षमता को बढ़ाता है - एक धागे को दूसरे धागे के संदर्भ में अपवादों को बढ़ाने की अनुमति देता है। उठाकर
SystemExit
, आप अंततः अजगर धागे को मार सकते हैं।
import threading
import ctypes
def _async_raise(tid, excobj):
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(excobj))
if res == 0:
raise ValueError("nonexistent thread id")
elif res > 1:
# """if it returns a number greater than one, you're in trouble,
# and you should call it again with exc=NULL to revert the effect"""
ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, 0)
raise SystemError("PyThreadState_SetAsyncExc failed")
class Thread(threading.Thread):
def raise_exc(self, excobj):
assert self.isAlive(), "thread must be started"
for tid, tobj in threading._active.items():
if tobj is self:
_async_raise(tid, excobj)
return
# the thread was alive when we entered the loop, but was not found
# in the dict, hence it must have been already terminated. should we raise
# an exception here? silently ignore?
def terminate(self):
# must raise the SystemExit type, instead of a SystemExit() instance
# due to a bug in PyThreadState_SetAsyncExc
self.raise_exc(SystemExit)
तो, यह "थ्रेड को किसी अन्य थ्रेड के संदर्भ में अपवाद को बढ़ाने के लिए" की अनुमति देता है और इस तरह, समाप्त धागा नियमित रूप से एक गर्भपात ध्वज की जांच के बिना समाप्ति को संभाल सकता है।
हालांकि, इसके मूल स्रोत के अनुसार , इस कोड के साथ कुछ समस्याएं हैं।
- अजगर बाइटकोड को निष्पादित करते समय अपवाद केवल उठाया जाएगा। यदि आपका थ्रेड एक देशी / अंतर्निहित अवरोधन फ़ंक्शन को कॉल करता है, तो अपवाद केवल तब उठाया जाएगा जब निष्पादन अजगर कोड पर लौट आए।
- यदि अंतर्निहित फ़ंक्शन आंतरिक रूप से PyErr_Clear () कहता है, तो एक समस्या यह भी है कि प्रभावी रूप से आपके लंबित अपवाद को रद्द कर दिया जाएगा। आप इसे फिर से बढ़ाने की कोशिश कर सकते हैं।
- केवल अपवाद प्रकारों को सुरक्षित रूप से उठाया जा सकता है। अपवाद उदाहरणों से अप्रत्याशित व्यवहार होने की संभावना है, और इस प्रकार प्रतिबंधित हैं।
- उदाहरण के लिए: t1.raise_exc (TypeError) और t1.raise_exc (TypeError ("blah"))।
- IMHO यह एक बग है, और मैंने इसे एक के रूप में रिपोर्ट किया। अधिक जानकारी के लिए, http://mail.python.org/pipermail/python-dev/2006-August/068158.html
- मैंने इस फ़ंक्शन को अंतर्निहित थ्रेड मॉड्यूल में उजागर करने के लिए कहा, लेकिन चूंकि ctypes एक मानक पुस्तकालय (2.5 के रूप में) बन गया है, और इस
सुविधा के कार्यान्वयन-अज्ञेय होने की संभावना नहीं है, इसलिए इसे
अनएक्सपोज्ड रखा जा सकता है ।
पीटर हिंटजेन्स - के संस्थापकों में से एक ØMQ -Project - कहते हैं, ØMQ का उपयोग करने और ताले, mutexes, घटनाओं आदि जैसे तुल्यकालन पुरातन से परहेज, sanest और securest तरह से मल्टी-थ्रेडेड कार्यक्रमों लिखने के लिए है:
http://zguide.zeromq.org/py:all#Multithreading-with-ZeroMQ
इसमें एक बच्चा धागा बताना शामिल है, कि उसे अपना काम रद्द करना चाहिए। यह एक QMQ-सॉकेट के साथ थ्रेड को लैस करने और उस सॉकेट पर पोलिंग के लिए एक संदेश के लिए किया जाएगा जिसमें यह कहा जाए कि इसे रद्द कर देना चाहिए।
लिंक .MQ के साथ बहु-थ्रेडेड पायथन कोड पर एक उदाहरण प्रदान करता है।
मान लें, कि आप एक ही फ़ंक्शन के कई थ्रेड्स करना चाहते हैं, तो यह IMHO आईडी द्वारा एक को रोकने के लिए सबसे आसान कार्यान्वयन है:
import time
from threading import Thread
def doit(id=0):
doit.stop=0
print("start id:%d"%id)
while 1:
time.sleep(1)
print(".")
if doit.stop==id:
doit.stop=0
break
print("end thread %d"%id)
t5=Thread(target=doit, args=(5,))
t6=Thread(target=doit, args=(6,))
t5.start() ; t6.start()
time.sleep(2)
doit.stop =5 #kill t5
time.sleep(2)
doit.stop =6 #kill t6
अच्छी बात यह है कि, आपके पास एक ही और विभिन्न प्रकार के कई कार्य हो सकते हैं, और उन सभी को रोक सकते हैं functionname.stop
यदि आप फ़ंक्शन का केवल एक धागा रखना चाहते हैं, तो आपको आईडी को याद रखने की आवश्यकता नहीं है। बस रोकें, अगर doit.stop
> 0।
बस @ SCB के विचार (जो वास्तव में मुझे क्या चाहिए था) को बनाने के लिए एक अनुकूलित फ़ंक्शन के साथ एक KillableThread उपवर्ग बनाने के लिए:
from threading import Thread, Event
class KillableThread(Thread):
def __init__(self, sleep_interval=1, target=None, name=None, args=(), kwargs={}):
super().__init__(None, target, name, args, kwargs)
self._kill = Event()
self._interval = sleep_interval
print(self._target)
def run(self):
while True:
# Call custom function with arguments
self._target(*self._args)
# If no kill signal is set, sleep for the interval,
# If kill signal comes in while sleeping, immediately
# wake up and handle
is_killed = self._kill.wait(self._interval)
if is_killed:
break
print("Killing Thread")
def kill(self):
self._kill.set()
if __name__ == '__main__':
def print_msg(msg):
print(msg)
t = KillableThread(10, print_msg, args=("hello world"))
t.start()
time.sleep(6)
print("About to kill thread")
t.kill()
स्वाभाविक रूप से, @SBC की तरह, थ्रेड रुकने के लिए नया लूप चलाने का इंतजार नहीं करता है। इस उदाहरण में, आप "किलिंग थ्रेड" संदेश को "थ्रेड को मारने के बारे में" के ठीक बाद छपे हुए देखेंगे, बजाय इसके कि थ्रेड को पूरा करने के लिए 4 और सेकंड इंतजार करें (क्योंकि हम पहले ही 6 सेकंड के लिए सो चुके हैं)।
KillableThread कंस्ट्रक्टर में दूसरा तर्क आपका कस्टम फ़ंक्शन (प्रिंट_एमएस यहां) है। आर्ग्स तर्क वे तर्क हैं जिनका उपयोग यहां फ़ंक्शन (("हैलो वर्ल्ड") को कॉल करते समय किया जाएगा।
जैसा कि @ Kozyarchuk के उत्तर में उल्लेख किया गया है , ट्रेस काम करता है। चूँकि इस उत्तर में कोई कोड नहीं है, यहाँ एक काम करने के लिए तैयार उदाहरण है:
import sys, threading, time
class TraceThread(threading.Thread):
def __init__(self, *args, **keywords):
threading.Thread.__init__(self, *args, **keywords)
self.killed = False
def start(self):
self._run = self.run
self.run = self.settrace_and_run
threading.Thread.start(self)
def settrace_and_run(self):
sys.settrace(self.globaltrace)
self._run()
def globaltrace(self, frame, event, arg):
return self.localtrace if event == 'call' else None
def localtrace(self, frame, event, arg):
if self.killed and event == 'line':
raise SystemExit()
return self.localtrace
def f():
while True:
print('1')
time.sleep(2)
print('2')
time.sleep(2)
print('3')
time.sleep(2)
t = TraceThread(target=f)
t.start()
time.sleep(2.5)
t.killed = True
यह मुद्रित होने के बाद बंद हो जाता है 1
और 2
। 3
छपा नहीं है।
आप एक प्रक्रिया में अपनी कमांड निष्पादित कर सकते हैं और फिर प्रक्रिया आईडी का उपयोग करके इसे मार सकते हैं। मुझे दो थ्रेड में से एक के बीच सिंक करने की आवश्यकता थी, जिसमें से एक अपने आप वापस नहीं आता है।
processIds = []
def executeRecord(command):
print(command)
process = subprocess.Popen(command, stdout=subprocess.PIPE)
processIds.append(process.pid)
print(processIds[0])
#Command that doesn't return by itself
process.stdout.read().decode("utf-8")
return;
def recordThread(command, timeOut):
thread = Thread(target=executeRecord, args=(command,))
thread.start()
thread.join(timeOut)
os.kill(processIds.pop(), signal.SIGINT)
return;
सेटडैमन (ट्रू) के साथ उप धागा शुरू करें।
def bootstrap(_filename):
mb = ModelBootstrap(filename=_filename) # Has many Daemon threads. All get stopped automatically when main thread is stopped.
t = threading.Thread(target=bootstrap,args=('models.conf',))
t.setDaemon(False)
while True:
t.start()
time.sleep(10) # I am just allowing the sub-thread to run for 10 sec. You can listen on an event to stop execution.
print('Thread stopped')
break
यह एक बुरा जवाब है, टिप्पणियों को देखें
यह कैसे करना है:
from threading import *
...
for thread in enumerate():
if thread.isAlive():
try:
thread._Thread__stop()
except:
print(str(thread.getName()) + ' could not be terminated'))
इसे कुछ सेकंड दें फिर आपका धागा बंद कर दिया जाना चाहिए। thread._Thread__delete()
विधि की भी जाँच करें ।
मैं thread.quit()
सुविधा के लिए एक विधि सुझाऊँगा । उदाहरण के लिए यदि आपके धागे में एक सॉकेट है, तो मैं quit()
आपके सॉकेट-हैंडल क्लास में एक विधि बनाने की सलाह दूंगा, सॉकेट को समाप्त करना, फिर thread._Thread__stop()
अपने अंदर चलाना quit()
।
_Thread__stop()
केवल एक धागे को रोक दिया जाता है , यह वास्तव में धागे को बंद नहीं करता है! ऐसा कभी न करें। पढ़ लिया है ।
यदि आपको वास्तव में एक उप-कार्य को मारने की क्षमता की आवश्यकता है, तो वैकल्पिक कार्यान्वयन का उपयोग करें। multiprocessing
और gevent
दोनों अंधाधुंध "थ्रेड" को मारने का समर्थन करते हैं।
पायथन का सूत्रण रद्द करने का समर्थन नहीं करता है। यहां तक की कोशिश नहीं करते। आपके कोड में गतिरोध, भ्रष्ट या लीक मेमोरी की संभावना है, या अन्य अनपेक्षित "दिलचस्प" हार्ड-टू-डीबग प्रभाव हैं जो शायद ही कभी और नॉनडेटर्मिनिस्टली होते हैं।