উত্তর:
পাইথন এবং যে কোনও ভাষায় হঠাৎ করে কোনও থ্রেড মেরে ফেলা খুব খারাপ প্যাটার্ন। নিম্নলিখিত বিষয়গুলি চিন্তা করুন:
আপনি যদি এটি সামর্থ্য করতে পারেন তবে এটি পরিচালনা করার দুর্দান্ত উপায়টি (যদি আপনি নিজের থ্রেডগুলি পরিচালনা করে থাকেন) হ'ল একটি প্রস্থান_প্রকাশের পতাকাটি যা প্রতিটি থ্রেডগুলি নিয়মিত বিরতিতে পরীক্ষা করে দেখবে যে এটি বেরোনোর সময় এসেছে কিনা।
উদাহরণ স্বরূপ:
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 )
( টোমর ফিলিবা দ্বারা কিলযোগ্য থ্রেডের উপর ভিত্তি করে of এর ফেরতের মান সম্পর্কে উদ্ধৃতিটি পাইথনেরPyThreadState_SetAsyncExc
একটি পুরানো সংস্করণ থেকে পাওয়া যায় ))
ডকুমেন্টেশনে উল্লিখিত হিসাবে, এটি কোনও ম্যাজিক বুলেট নয় কারণ থ্রেড পাইথন ইন্টারপ্রেটারের বাইরে ব্যস্ত থাকলে এটি বাধাকে ধরবে না।
এই কোডটির একটি ভাল ব্যবহারের প্যাটার্নটি হ'ল থ্রেডটিকে একটি নির্দিষ্ট ব্যতিক্রম ধরা এবং ক্লিনআপ করা। এইভাবে, আপনি কোনও কাজে বাধা দিতে পারেন এবং এখনও সঠিক পরিষ্কার-পরিচ্ছন্নতা রাখতে পারেন।
SO_REUSEADDR
এড়াতে আপনি সকেট বিকল্পটি ব্যবহার করতে পারেন Address already in use
।
None
পরিবর্তে 0
জন্য res != 1
কেস, এবং আমি কল করতে ছিল ctypes.c_long(tid)
এবং পাস যে কোনো ctypes TID সরাসরি বদলে কাজ করে।
এটি করার জন্য কোনও অফিসিয়াল এপিআই নেই, না।
থ্রেড, যেমন pthread_kill, বা টার্মিনেটথ্রেডকে মেরে ফেলার জন্য আপনার প্ল্যাটফর্ম API ব্যবহার করা উচিত। আপনি যেমন এপিআই অ্যাক্সেস করতে পারেন উদাহরণস্বরূপ পাইথনউইন বা সিটাইপসের মাধ্যমে।
লক্ষ্য করুন যে এটি স্বভাবতই অনিরাপদ। এটি সম্ভবত সিদ্ধান্তহীন আবর্জনা (স্ট্যাক ফ্রেমের স্থানীয় ভেরিয়েবলগুলি যা আবর্জনা হয়ে ওঠে) ডেকে আনে এবং অচলাবস্থার কারণ হতে পারে, যদি থ্রেডটি মেরে ফেলা হয় তবে জিআইএল এটি মারা যাওয়ার সময় রয়েছে।
একজন multiprocessing.Process
করতে পারেনp.terminate()
যে ক্ষেত্রে আমি কোনও থ্রেডটি মেরে ফেলতে চাই, তবে পতাকা / লক / সিগন্যাল / সেমোফোর / ইভেন্টগুলি / যাই হোক না কেন ব্যবহার করতে চাই না, আমি থ্রেডগুলি সম্পূর্ণ প্রস্ফুটিত প্রসেসে প্রচার করি। কোডের জন্য যা কেবল কয়েকটি থ্রেড ব্যবহার করে ওভারহেডটি খারাপ হয় না।
উদাহরণস্বরূপ, সহজেই সাহায্যকারী "থ্রেডগুলি" সমাপ্ত করতে কার্যকর হবে যা I / O ব্লকিং কার্যকর করে
রূপান্তর তুচ্ছ হল: সংশ্লিষ্ট কোড ইন সমস্ত প্রতিস্থাপন threading.Thread
সঙ্গে multiprocessing.Process
এবং সমস্ত queue.Queue
সঙ্গে multiprocessing.Queue
এবং প্রয়োজনীয় কল যোগ p.terminate()
আপনার পিতা বা মাতা প্রক্রিয়া যার তার সন্তানকে হত্যা করতে চায়p
এর জন্য পাইথন ডকুমেন্টেশনmultiprocessing
দেখুন ।
multiprocessing
দুর্দান্ত, তবে সচেতন থাকুন যে নতুন প্রক্রিয়াটি যুক্তিযুক্ত pick সুতরাং আর্গুমেন্টগুলির মধ্যে একটি যদি বাছাইযোগ্য কিছু না (যেমন একটি logging.log
) এটি ব্যবহার করা ভাল ধারণা নাও হতে পারে multiprocessing
।
multiprocessing
উইন্ডোজে নতুন প্রক্রিয়াতে যুক্তিগুলি যুক্ত হয়েছে, তবে লিনাক্স সেগুলি অনুলিপি করার জন্য দৃking় ব্যবহার করে (পাইথন ৩.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 - কেলেবল থ্রেড (পাইথন রেসিপি) এর উপর ভিত্তি করে
আপনাকে পাইথ্রেডস্টেট_সেট্যাসিএনএক্সসি () কল করতে হবে, যা কেবল সিটাইপের মাধ্যমে উপলব্ধ।
এটি কেবল পাইথন ২.7.৩ এ পরীক্ষা করা হয়েছে, তবে এটি সাম্প্রতিক অন্যান্য ২.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()
সঠিকভাবে বাস্তবায়নের জন্য এটি অনেক কাজ হবে এবং এটি দোভাষী হিসাবে ধীরগতির হয়ে যাবে।
কোনও থ্রেডকে সহযোগিতা না করে জোর করে কখনও হত্যা করা উচিত নয়।
থ্রেডকে হত্যা করা এমন কোনও গ্যারান্টি সরিয়ে দেয় যা চেষ্টা করে / অবশেষে ব্লক সেট আপ করে দেয় যাতে আপনি লকগুলি তালাবদ্ধ রাখতে পারেন, ফাইলগুলি খোলা থাকতে পারে ইত্যাদি remove
কেবলমাত্র যখন আপনি তর্ক করতে পারেন যে জোর করে থ্রেডগুলি হত্যা করা একটি ভাল ধারণাটি হ'ল একটি প্রোগ্রাম দ্রুত মারা যায়, তবে কখনও একক থ্রেড হয় না।
পাইথনে, আপনি কেবল কোনও থ্রেড সরাসরি মারতে পারবেন না।
থ্রেডিং ব্যবহার না করে যদি আপনার সত্যিই কোনও থ্রেড (!) থাকা দরকার না হয় তবে আপনি কী করতে পারেন প্যাকেজটি হ'ল মাল্টিপ্রসেসিং প্যাকেজটি ব্যবহার করা । এখানে, একটি প্রক্রিয়া হত্যা করতে, আপনি কেবল পদ্ধতিটি কল করতে পারেন:
yourProcess.terminate() # kill the process!
পাইথন আপনার প্রক্রিয়াটি মেরে ফেলবে ( TerminateProcess()
কলটি দিয়ে উইন্ডোজ চলাকালীন সিগ্টারএম সিগন্যালের মাধ্যমে ইউনিক্সে )। একটি সারি বা পাইপ ব্যবহার করার সময় এটি ব্যবহার করার জন্য মনোযোগ দিন! (এটি কাতারে / পাইপে ডেটাটিকে দূষিত করতে পারে)
নোট করুন এবং যথাক্রমে একই পদ্ধতিতে multiprocessing.Event
এবং multiprocessing.Semaphore
কাজটি in আসলে, প্রথমগুলি হ'ল পরের ক্লোনগুলি।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()
ইঙ্গিত করবেন) এবং আমার মতে প্রস্থানটি হ্যান্ডল করার কোডটি উল্লেখযোগ্যভাবে সহজ is ।
আপনি যদি কোনও সুতো না মারেন তবে ভাল। থ্রেডের চক্রের মধ্যে "চেষ্টা" ব্লকটি প্রবর্তন করা এবং আপনি থ্রেডটি থামাতে চাইলে একটি ব্যতিক্রম ছুঁড়ে ফেলার উপায় হতে পারে (উদাহরণস্বরূপ বিরতি / রিটার্ন / ... যা আপনার / যখন / ... বন্ধ করে দেয়)। আমি এটি আমার অ্যাপ্লিকেশনটিতে ব্যবহার করেছি এবং এটি কাজ করে ...
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
থ্রেডে সেট হয়ে যাওয়ার জন্য চেকগুলি ইনজেক্ট করার এটি একটি চতুর উপায় । মনে রাখবেন যে এখানে অন্যান্য সমাধানগুলির বেশিরভাগের মতো এটি আসলে একটি ব্লকিং কলকে বাধাগ্রস্ত করবে না, যেহেতু ট্রেস ফাংশনটি কেবল তখনই একটি নতুন স্থানীয় সুযোগ প্রবেশ করানো হয় called এছাড়াও লক্ষণীয় যে 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)
সুতরাং, এটি "থ্রেডটিকে অন্য থ্রেডের প্রসঙ্গে ব্যতিক্রম বাড়াতে" অনুমতি দেয় এবং এইভাবে, সমাপ্ত থ্রেড নিয়মিত কোনও বিসর্জনিত পতাকাটি পরীক্ষা না করেই সমাপ্তি পরিচালনা করতে পারে।
তবে এর আসল উত্স অনুসারে এই কোডটি নিয়ে কিছু সমস্যা রয়েছে।
- পাইথন বাইটকোড কার্যকর করার সময় ব্যতিক্রমগুলি উত্থাপিত হবে। যদি আপনার থ্রেডটি কোনও দেশীয় / অন্তর্নির্মিত ব্লকিং ফাংশনটিকে কল করে, কেবলমাত্র অজগর কোডটিতে মৃত্যুদন্ড কার্যকর হলেই ব্যতিক্রম উত্থাপিত হবে।
- অন্তর্নির্মিত ফাংশনটি অভ্যন্তরীণভাবে পাইআর_ক্র্লেয়ার () কল করে যদি একটি সমস্যা রয়েছে, যা কার্যকরভাবে আপনার মুলতুবি ব্যতিক্রম বাতিল করে দেবে। আপনি এটি আবার বাড়াতে চেষ্টা করতে পারেন।
- কেবল ব্যতিক্রম প্রকারগুলি নিরাপদে উত্থাপিত হতে পারে। ব্যতিক্রম উদাহরণগুলি অপ্রত্যাশিত আচরণের কারণ হতে পারে এবং এইভাবে সীমাবদ্ধ।
- উদাহরণস্বরূপ: t1.raise_exc (TypeError) এবং t1.raise_exc (TypeError ("blah")) নয়।
- আইএমএইচও এটি একটি বাগ, এবং আমি এটি হিসাবে রিপোর্ট করেছি। আরও তথ্যের জন্য, http://mail.python.org/pipermail/python-dev/2006- অগাস্ট / 068158.html
- আমি বিল্ট-ইন থ্রেড মডিউলটিতে এই ফাংশনটি প্রকাশ করতে বলেছিলাম, তবে যেহেতু সিটিপস একটি স্ট্যান্ডার্ড লাইব্রেরি হয়েছে (২.৩ হিসাবে), এবং এই
বৈশিষ্ট্যটি বাস্তবায়ন- অজানস্টিক হওয়ার সম্ভাবনা নেই, তাই এটি অনস্পষ্ট অবস্থায় রাখতে পারে
।
পিএমর হিন্টজেন্সস - এমকিউ- প্রকল্পের অন্যতম প্রতিষ্ঠাতা - বলেছেন, Ø এমকিউ ব্যবহার করা এবং লক, মিউটেক্স, ইভেন্ট ইত্যাদির মতো সিঙ্ক্রোনাইজেশন আদিমতা এড়ানো, একাধিক থ্রেডযুক্ত প্রোগ্রাম লেখার সানেষ্ট এবং সুরক্ষিত উপায়:
http://zguide.zeromq.org/py:all#Multithreading-with-ZeroMQ
এর মধ্যে একটি শিশু থ্রেড বলাও উচিত, এটির কাজটি বাতিল করা উচিত। এটি থ্রেডটি এমকিউ-সকেটের সাথে সজ্জিত করে এবং সেই সকেটে এই বার্তাটি বাতিল করার কথা বলে ভোট দেওয়ার মাধ্যমে পোলিং করা হবে।
লিঙ্কটি এমকিউ সহ মাল্টি-থ্রেডেড পাইথন কোডের একটি উদাহরণও সরবরাহ করে।
মনে করে, আপনি একই ফাংশনের একাধিক থ্রেড রাখতে চান, এটি আইডিতে একটিকে থামানো সবচেয়ে সহজ বাস্তবায়ন 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।
কাস্টমাইজড ফাংশন সহ কিলাবলথ্রেড সাবক্লাস তৈরি করতে কেবল @ এসসিবির ধারণাটি (যা আমার যা প্রয়োজন ঠিক তেমনটিই তৈরি করা):
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()
স্বাভাবিকভাবেই, @ এসবিসি-র মতো, থ্রেডটি থামাতে নতুন লুপটি চালানোর জন্য অপেক্ষা করে না। এই উদাহরণে, আপনি থ্রেডটি সম্পূর্ণ হওয়ার জন্য আরও 4 সেকেন্ড অপেক্ষা না করে "থ্রেড মারতে চলেছেন" এর পরে ঠিক "কিলিং থ্রেড" বার্তাটি মুদ্রিত দেখতে পাবেন (যেহেতু আমরা ইতিমধ্যে 6 সেকেন্ডের জন্য ঘুমিয়েছি)।
কিল্যাবলথ্রেড কনস্ট্রাক্টরের দ্বিতীয় যুক্তি হ'ল আপনার কাস্টম ফাংশন (এখানে print_msg)। আরগস আর্গুমেন্টটি সেই যুক্তি যা এখানে ফাংশন (("হ্যালো ওয়ার্ল্ড")) কল করার সময় ব্যবহৃত হবে।
@ কোজিরুকুকের উত্তরে যেমন উল্লেখ করা হয়েছে , ট্রেস ইনস্টল করার কাজ রয়েছে। যেহেতু এই উত্তরে কোনও কোড নেই, তাই এখানে ব্যবহারের জন্য প্রস্তুত উদাহরণ রয়েছে:
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
উভয়ই নির্বিচারে একটি "থ্রেড" হত্যার পক্ষে সমর্থন করে।
পাইথনের থ্রেডিং বাতিলকরণ সমর্থন করে না। এমনকি চেষ্টা করবেন না. আপনার কোডটি অচলাবস্থা, দুর্নীতিগ্রস্থ বা মেমরি ফাঁস হওয়ার সম্ভাবনা রয়েছে বা অন্যান্য অপ্রত্যাশিত "আকর্ষণীয়" হার্ড-টু-ডিবাগ প্রভাব রয়েছে যা বিরল এবং অ-সংজ্ঞায়িতভাবে ঘটে।