Yanıtlar:
Bir ipliği Python'da ve herhangi bir dilde aniden öldürmek genellikle kötü bir modeldir. Aşağıdaki durumları düşünün:
Ödeyebiliyorsanız bunu yapmanın güzel yolu (kendi iş parçacıklarınızı yönetiyorsanız), her iş parçacığının çıkma zamanının gelip gelmediğini görmek için düzenli aralıklarla kontrol ettiği bir exit_request bayrağına sahip olmaktır.
Örneğin:
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()
Bu kodda, stop()
çıkmasını istediğinizde iş parçacığını çağırmanız ve iş parçacığının kullanarak doğru şekilde çıkmasını beklemeniz gerekir join()
. İplik durdurma bayrağını düzenli aralıklarla kontrol etmelidir.
Bununla birlikte, bir iş parçacığını gerçekten öldürmeniz gerektiğinde durumlar vardır. Bir örnek, uzun aramalar için meşgul olan harici bir kütüphaneyi sararken ve onu kesmek istediğinizde verilebilir.
Aşağıdaki kod (bazı kısıtlamalarla) Python iş parçacığında bir İstisna oluşturmaya izin verir:
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 )
( Tomer Filiba tarafından yazılan Killable Threads temel alınmıştır. Dönüş değeri hakkındaki alıntı , Python'un eski bir versiyonundanPyThreadState_SetAsyncExc
geliyor gibi görünüyor .)
Belgelerde belirtildiği gibi, bu sihirli bir mermi değildir, çünkü iplik Python yorumlayıcısının dışında meşgulse, kesintiyi yakalamaz.
Bu kodun iyi bir kullanım şekli, iş parçacığının belirli bir özel durumu yakalaması ve temizleme işlemini gerçekleştirmesidir. Bu şekilde, bir görevi kesintiye uğratabilir ve yine de düzgün bir şekilde temizleyebilirsiniz.
SO_REUSEADDR
önlemek için soket seçeneğini kullanabilirsiniz Address already in use
.
None
yerine 0
ilişkin res != 1
söz ve ben aramak zorunda ctypes.c_long(tid)
ve herhangi ctypes doğrudan tid yerine işlev olduğunu geçmektedir.
Bunu yapacak resmi bir API yok, hayır.
İş parçacığını öldürmek için platform API'sini kullanmanız gerekir, örn. Pthread_kill veya TerminateThread. Bu tür API'lara örneğin pythonwin veya ctypes aracılığıyla erişebilirsiniz.
Bunun doğal olarak güvensiz olduğuna dikkat edin. Muhtemelen toplanamayan çöplere (çöp haline gelen yığın çerçevelerinin yerel değişkenlerinden) yol açacaktır ve eğer öldürülmekte olan iplik öldürüldüğü noktada GIL varsa, kilitlenmelere yol açabilir.
Bir multiprocessing.Process
kutup.terminate()
Bir iş parçacığını öldürmek istediğim, ancak bayrakları / kilitleri / sinyalleri / semaforları / olayları / diğerlerini kullanmak istemediğim durumlarda, iş parçacıklarını tam üflemeli işlemlere teşvik ediyorum. Sadece birkaç iş parçacığından yararlanan kod için ek yük o kadar da kötü değildir.
Örneğin, bu, G / Ç'yi engelleyen yardımcı "iş parçacıklarını" kolayca sonlandırmak için kullanışlıdır
Dönüşüm Önemsiz: İlgili kodunda tümünü değiştir threading.Thread
ile multiprocessing.Process
ve tüm queue.Queue
ile multiprocessing.Queue
ve gerekli aramaları eklemek p.terminate()
onun çocuğu öldürmek istiyor Ebeveyninizin sürecinep
multiprocessing
güzel, ancak argümanların yeni sürece yönlendirildiğini unutmayın. Dolayısıyla, argümanlardan biri seçilemez bir şeyse (a gibi logging.log
) kullanmak iyi bir fikir olmayabilir multiprocessing
.
multiprocessing
argümanlar Windows'taki yeni işleme getirilir, ancak Linux bunları kopyalamak için çatal kullanır (Python 3.7, diğer sürümlerden emin değilsiniz). Böylece Linux üzerinde çalışan ancak Windows'ta turşu hatalarını yükselten kod elde edersiniz.
multiprocessing
giriş ile zor bir iştir. Kullanmanız gerekiyor QueueHandler
( bu eğiticiye bakın ). Zor yoldan öğrendim.
Tüm programı sonlandırmaya çalışıyorsanız, iş parçacığını "arka plan programı" olarak ayarlayabilirsiniz. bkz. Thread.daemon
Diğerlerinin de belirttiği gibi, norm bir durdurma bayrağı koymaktır. Hafif bir şey için (Thread'in alt sınıfı yok, global değişken yok), lambda geri çağırma bir seçenektir. (İçindeki parantezleri not edin 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()
Her zaman yıkanan ( ) print()
bir pr()
işlevle değiştirmek sys.stdout.flush()
, kabuk çıktısının hassasiyetini artırabilir.
(Yalnızca Windows / Eclipse / Python3.3 üzerinde test edilmiştir)
pr()
işlevi?
Bu thread2 - fırınlanabilir iplikleri temel alır (Python tarifi)
Yalnızca ctypes aracılığıyla kullanılabilen PyThreadState_SetasyncExc () öğesini çağırmanız gerekir.
Bu sadece Python 2.7.3 üzerinde test edilmiştir, ancak diğer son 2.x sürümleriyle de çalışması muhtemeldir.
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
temizlemek için böyle bir şey kullanıyorum, böylece temizlik şansı var. Bundan sonra HALA asılı kalırlarsa SystemExit
, uygundur veya işlemi bir terminalden öldürün.
pthread_cleanup_push()/_pop()
doğru bir şekilde uygulanması çok iş olurdu ve yorumlayıcıyı belirgin şekilde yavaşlatacaktır.
Bir ipliği onunla işbirliği yapmadan asla zorla öldürmemelisiniz.
Bir iş parçacığını öldürmek, kilitleri kilitli, dosyaları açık vb. Bırakabilmeniz için kurulumu / sonlandırmayı engellemeyi garanti eden tüm garantileri kaldırır.
Zorla iş parçacığı öldürmenin iyi bir fikir olduğunu iddia edebileceğiniz tek zaman, bir programı hızlı bir şekilde öldürmek, ancak asla tek bir iş parçacığını öldürmektir.
Python'da, bir Konuyu doğrudan öldüremezsiniz.
Gerçekten bir iş parçacığına (!) İhtiyacınız DEĞİLSE, iş parçacığı paketini kullanmak yerine yapabileceğiniz çok işlemcili paketi kullanmaktır . Burada, bir işlemi öldürmek için yöntemi çağırabilirsiniz:
yourProcess.terminate() # kill the process!
Python işleminizi öldürecektir (Unix'te SIGTERM sinyaliyle, Windows'da TerminateProcess()
çağrı yoluyla ). Bir Kuyruk veya Pipo kullanırken kullanmaya dikkat edin! (Kuyruk / Borudaki verileri bozabilir)
Not olduğunu multiprocessing.Event
ve multiprocessing.Semaphore
aynı şekilde tam olarak çalışma threading.Event
ve threading.Semaphore
sırasıyla. Aslında, ilki latterin klonlarıdır.
GERÇEKTEN bir Konu kullanmanız gerekiyorsa, onu doğrudan öldürmenin bir yolu yoktur. Ancak yapabileceğiniz şey, bir "daemon thread" kullanmaktır . Aslında, Python'da, bir Konu arka plan programı olarak işaretlenebilir :
yourThread.daemon = True # set the Thread as a "daemon thread"
Hiçbir canlı daemon olmayan iş parçacığı kalmadığında ana programdan çıkılır. Başka bir deyişle, ana iş parçanız (tabii ki bir daemon olmayan iş parçacığı) işlemlerini tamamladığında, hala çalışan bazı daemon iş parçacıkları olsa bile programdan çıkılır.
Yöntem çağrılmadan daemon
önce bir Konu ayarlamak gerektiğini unutmayın start()
!
Tabii ki daemon
bile kullanabilirsiniz ve kullanmalısınız multiprocessing
. Burada, ana süreç çıktığında, tüm daemonik alt süreçlerini sonlandırmaya çalışır.
Son olarak, lütfen, unutmayın sys.exit()
ve os.kill()
seçenek değildir.
İş parçacığından çıkacak iş parçacığına izleme yükleyerek bir iş parçacığını öldürebilirsiniz. Olası bir uygulama için ekteki bağlantıya bakın.
Eğer time.sleep()
iş parçacığınızın bir parçası olarak açıkça çağırıyorsanız (diyelim ki harici hizmet çağırma), Phillipe'nin yöntemindeki bir zaman aşımı, nerede olursanız olun event
' wait()
yönteminde zaman aşımı kullanmaktır.sleep()
Örneğin:
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()
Sonra çalıştırmak için
t = KillableThread(sleep_interval=5)
t.start()
# Every 5 seconds it prints:
#: Do Something
t.kill()
#: Killing Thread
Olayı ing olarak kullanmak ve düzenli olarak kontrol etmek wait()
yerine kullanmanın avantajı, sleep()
daha uzun uyku aralıklarında programlayabilmeniz, iplik neredeyse anında durur (aksi halde olursanız sleep()
) ve bence, çıkışla ilgili kod önemli ölçüde daha basittir .
Bir ipliği öldürmezseniz daha iyi olur. Bir yol, iş parçacığının döngüsüne bir "try" bloğu eklemek ve iş parçacığını durdurmak istediğinizde bir istisna atmak olabilir (örneğin, for / while / ... komutunu durduran bir break / return / ...). Bunu uygulamamda kullandım ve işe yarıyor ...
Thread.stop
Aşağıdaki örnek kodda gösterildiği gibi bir yöntem uygulamak kesinlikle mümkündür :
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
Sınıf yaklaşık% 33 daha hızlı kod çalıştırmasına görünen Thread2
sınıfın.
self.__stop
iş parçacığına yerleştirilmek üzere kontroller enjekte etmenin akıllıca bir yoludur . İzleme işlevinin yalnızca yeni bir yerel kapsam girildiğinde çağrıldığından, buradaki diğer çözümlerin çoğu gibi, aslında bir engelleme çağrısını kesintiye uğratmayacağını unutmayın. Ayrıca, sys.settrace
hata ayıklayıcıları, profilleri vb. Uygulamak için gerçekten amaçlandığı ve bu şekilde CPython'un bir uygulama detayı olarak kabul edildiği ve diğer Python uygulamalarında varlığının garanti edilmediği de belirtilmelidir.
Thread2
kodu yaklaşık on kat daha yavaş çalıştırmasıdır. Bazı insanlar bunu hala kabul edilebilir bulabilir.
from ctypes import *
pthread = cdll.LoadLibrary("libpthread-2.15.so")
pthread.pthread_cancel(c_ulong(t.ident))
t senin olan Thread
nesne.
Python kaynağını okuyun ( Modules/threadmodule.c
ve Python/thread_pthread.h
) Thread.ident
bir pthread_t
tür olduğunu görebilirsiniz, böylece pthread
python kullanımında yapabileceğiniz her şeyi yapabilirsiniz libpthread
.
Bir iş parçacığını öldürmek için aşağıdaki geçici çözüm kullanılabilir:
kill_threads = False
def doSomething():
global kill_threads
while True:
if kill_threads:
thread.exit()
......
......
thread.start_new_thread(doSomething, ())
Bu, kodu başka bir modülde yazılmış olan evreleri ana evreden sonlandırmak için bile kullanılabilir. Bu modülde global bir değişken bildirebilir ve bu modülde ortaya çıkan evreleri sonlandırmak için kullanabiliriz.
Bunu genellikle program çıkışındaki tüm evreleri sonlandırmak için kullanırım. Bu, iş parçacıklarını sonlandırmak için mükemmel bir yol olmayabilir, ancak yardımcı olabilir.
Bu oyuna çok geç kaldım, ama benzer bir soru ile güreştim ve aşağıdakiler hem benim için mükemmel bir şekilde sorunu çözmek için görünüyor VE ben de arka plana alınan alt-iş parçacığı çıktığında bazı temel iş parçacığı durumu denetimi ve temizliği yapmama izin veriyor:
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()
Verim:
0
1
KILL MAIN THREAD: 140013208254208
'CLEANLY' kill sub-thread with value: 2 [THREAD: 140013674317568]
SystemExit
üzerindeki after_timeout
iplik (sadece bu örnekte çıkmak için eski bekliyor) ana iş parçacığı için her şeyi?
SystemExit
yalnızca iki özel özelliğe sahiptir: bir geri izleme oluşturmaz (herhangi bir iş parçacığı fırlatarak çıktığında) ve ana iş parçacığı fırlatılarak çıkarsa çıkış durumunu ayarlar (yine de diğer daemon olmayan iş parçacıklarını beklerken çıkışa doğru).
Eklemek istediğim bir şey , lib Python iş parçacığında resmi belgeleri okursanız , Paolo Rovelli'nin bahsettiği bayrakla, iş parçacıklarının aniden sona ermesini istemediğinizde "şeytani" iş parçacıklarının kullanılmasından kaçınılmasıdır .
Resmi belgelerden:
Daemon iş parçacıkları kapatma sırasında aniden durdurulur. Kaynakları (açık dosyalar, veritabanı işlemleri vb.) Doğru şekilde serbest bırakılmayabilir. İş parçacıklarınızın zarif bir şekilde durmasını istiyorsanız, onları daemon olmayan yapın ve bir Etkinlik gibi uygun bir sinyal mekanizması kullanın.
Daemonic iş parçacığı oluşturmanın uygulamanıza bağlı olduğunu düşünüyorum, ancak genel olarak (ve bence) onları öldürmekten veya onları daemon yapmaktan daha iyi. Çoklu işlemlerde şunları kullanabilirsiniz:is_alive()
işlemde, işlem durumunu kontrol etmek ve bitirmek için "sonlandırmak" için kullanabilirsiniz (Ayrıca GIL sorunlarından kaçınabilirsiniz). Ancak bazen kodunuzu Windows'da yürüttüğünüzde daha fazla sorun bulabilirsiniz.
Ve "canlı iş parçacıkları" varsa, Python yorumlayıcısının onları beklemeye çalışacağını unutmayın. (Bu daemonic nedeniyle aniden bitmezse size yardımcı olabilir).
Bu amaçla yapılmış bir kütüphane var, stopit . Her ne kadar burada listelenen aynı uyarılar hala geçerli olsa da, en azından bu kütüphane belirtilen hedefe ulaşmak için düzenli ve tekrarlanabilir bir teknik sunmaktadır.
Oldukça eski olsa da, bu bazıları için kullanışlı bir çözüm olabilir:
İş parçacığının modül işlevini genişleten küçük bir modül - bir iş parçacığının başka bir iş parçacığı bağlamında istisnalar oluşturmasına izin verir. Yükselterek
SystemExit
, nihayet piton ipliklerini öldürebilirsin.
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)
Bu nedenle, "iş parçacığı başka bir iş parçacığı bağlamında istisnaları artırmaya" izin verir ve bu yolla sonlandırılmış iş parçacığı, durdurma bayrağını düzenli olarak denetlemeden sonlandırmayı işleyebilir.
Ancak, orijinal kaynağına göre , bu kodla ilgili bazı sorunlar var.
- Kural dışı durum yalnızca python bayt kodu yürütülürken ortaya çıkar. İleti diziniz yerel / yerleşik engelleme işlevini çağırırsa, istisna yalnızca yürütme python koduna döndüğünde ortaya çıkar.
- Yerleşik işlev dahili olarak PyErr_Clear () öğesini çağırırsa, bu durum bekleyen istisnanızı etkili bir şekilde iptal ederse de bir sorun vardır. Tekrar yükseltmeyi deneyebilirsiniz.
- Yalnızca kural dışı durum türleri güvenle oluşturulabilir. İstisna örneklerinin beklenmedik davranışlara neden olması muhtemeldir ve bu nedenle sınırlıdır.
- Örneğin: t1.raise_exc (TypeError ("blah")) değil, t1.raise_exc (TypeError).
- IMHO bir hata ve bunu bir rapor ettim. Daha fazla bilgi için http://mail.python.org/pipermail/python-dev/2006-Ağustos/068158.html
- Yerleşik iş parçacığı modülünde bu işlevi ortaya çıkarmak istedim, ancak ctypes (2.5'ten itibaren) standart bir kitaplık haline geldiğinden ve bu
özelliğin uygulamadan bağımsız olması muhtemel olmadığından,
maruz kalmayabilir .
Pieter Hintjens - kurucularından ØMQ kullanarak ve kilitler, muteksler, olaylar vb. Gibi senkronizasyon ilkellerinden kaçınmanın çok iş parçacıklı programlar yazmanın en güvenli ve güvenli yoludur:
http://zguide.zeromq.org/py:all#Multithreading-with-ZeroMQ
Bu, çocuk iş parçacığının çalışmasını iptal etmesi gerektiğini bildirmeyi içerir. Bu, iş parçacığının bir ØMQ soketi ile donatılması ve iptal edilmesi gerektiğini söyleyen bir mesaj için o sokette yoklama yapılmasıyla yapılır.
Bağlantı ayrıca ØMQ ile çok iş parçacıklı python koduna bir örnek sağlar.
Aynı işlevin birden çok iş parçacığına sahip olmak istediğinizi varsayarsak, bu IMHO'yu id ile durdurmak için en kolay uygulamadır:
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
Güzel olan şey burada, aynı ve farklı işlevlerden birden fazlasına sahip olabilir ve hepsini durdurabilirsiniz. functionname.stop
Eğer işlevin sadece bir iş parçacığına sahip olmak istiyorsanız o zaman kimliği hatırlamanıza gerek yoktur. Sadece doit.stop
> 0 ise dur .
Özelleştirilmiş bir işleve sahip bir KillableThread alt sınıfı oluşturmak için @ SCB'nin fikrini (tam da ihtiyacım olan şeydi) oluşturmak için:
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()
Doğal olarak, @SBC'de olduğu gibi, iş parçacığı durdurmak için yeni bir döngü çalıştırmak için beklemez. Bu örnekte, iş parçacığının tamamlanması için 4 saniye daha beklemek yerine "İş parçacığını öldürmek üzere" ifadesinin hemen ardından "İş parçacığı öldürme" mesajının yazdırıldığını görürsünüz (zaten 6 saniye uyuduk).
KillableThread yapıcısındaki ikinci argüman sizin özel işlevinizdir (print_msg burada). Args argümanı, işlevi (("merhaba dünya")) çağırırken kullanılacak argümanlardır.
Kozyarchuk en @ belirtildiği gibi cevap , yüklemeden iz çalışır. Bu yanıt kod içermediğinden, çalışmaya hazır bir örnek:
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
Yazdırdıktan sonra durur 1
ve 2
. 3
yazdırılmaz.
Komutunuzu bir işlemde yürütebilir ve ardından işlem kimliğini kullanarak öldürebilirsiniz. Biri kendi başına dönmeyen iki iş parçacığı arasında eşitlemek gerekiyordu.
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;
Alt iş parçacığını setDaemon (True) ile başlatın.
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
Bu kötü bir cevap, yorumlara bakın
Bunu nasıl yapacağınız aşağıda açıklanmıştır:
from threading import *
...
for thread in enumerate():
if thread.isAlive():
try:
thread._Thread__stop()
except:
print(str(thread.getName()) + ' could not be terminated'))
Birkaç saniye verin, sonra ipliğin durdurulması gerekir. thread._Thread__delete()
Yöntemi de kontrol edin .
thread.quit()
Kolaylık sağlamak için bir yöntem öneriyorum . Örneğin, iş parçacığınızda bir soket varsa quit()
, soket tanıtıcı sınıfınızda bir yöntem oluşturmanızı , soketi sonlandırmanızı ve ardından bir thread._Thread__stop()
iç kısmını çalıştırmanızı öneririm quit()
.
_Thread__stop()
sadece bir iş parçacığı durmuş olarak işaretler , aslında iş parçacığını durdurmaz! Bunu asla yapma. Bir okuyun .
Bir alt görevi gerçekten öldürme yeteneğine ihtiyacınız varsa, alternatif bir uygulama kullanın. multiprocessing
vegevent
her ikisi de bir "iş parçacığını" gelişigüzel öldürmeyi destekler.
Python'un iş parçacığı iptali iptal etmeyi desteklemez. Deneme bile. Kodunuzun büyük olasılıkla kilitlenmesi, bozulması veya belleğe sızması veya nadiren ve belirsiz bir şekilde meydana gelen istenmeyen "ilginç" hata ayıklaması zor etkileri olabilir.