setDaemon
th.setDaemon(True) 默认参数为 False
setDaemon(True)将线程声明为守护线程,必须在start() 方法调用之前设置,如果不设置为守护线程程序会被无限挂起。当没有存活的非守护进程时,整个python程序才会退出。
总结:
如果主线程执行完以后,还有其他非守护线程,主线程是不会退出的,会被无限挂起;必须将线程声明为守护线程之后,如果队列中的数据运行完了,那么整个程序想什么时候退出就退出,不用等待。
代码示例:
# -*- coding:utf-8 -*-
# @Time : 2021/1/6 10:07
# @Author : hllyzms
import ctypes
import inspect
import threading
import time
from threading import Thread
class SingletonData(object):
_instance_lock = threading.Lock()
def __new__(cls, *args, **kwargs):
if not hasattr(SingletonData, "_instance"):
with SingletonData._instance_lock:
if not hasattr(SingletonData, "_instance"):
SingletonData._instance = object.__new__(cls)
ins = SingletonData._instance
return ins
return SingletonData._instance
def __init__(self, info_dict=dict()):
self.mainth = False
self.childth = False
singleton = SingletonData()
class DemoThread(Thread):
def run(self):
if singleton.mainth:
return
singleton.mainth = True
for i in range(1,5):
print("DemoThread:",i)
singleton.childth = i
if hasattr(singleton, "th"):
th = getattr(singleton, "th")
if th.is_alive():
stop_thread(th)
singleton.th = Thread(target=thdemo,args=(i,))
singleton.th.start()
count = 0
while True:
if count ==5:
print("DemoThread 退出")
return
count += 1
if not singleton.mainth:
print("DemoThread退出 close")
return
if singleton.childth == i:
time.sleep(1)
else:
break
singleton.mainth = False
def thdemo(i):
num = 1
while singleton.childth == i:
print("child",i,num)
num += 1
# if num > 4:
# break
time.sleep(1)
def _async_raise(tid, exctype):
# todo 强制退出线程 忽略掉报错
try:
"""raises the exception, performs cleanup if needed"""
tid = ctypes.c_long(tid)
if not inspect.isclass(exctype):
exctype = type(exctype)
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(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(tid, None)
raise SystemError("PyThreadState_SetAsyncExc failed")
except:
pass
def stop_thread(thread):
_async_raise(thread.ident, SystemExit)
if __name__ == '__main__':
th = DemoThread()
th.setDaemon(True)
th.start()
th.join()
time.sleep(3)
运行结果:
DemoThread: 1
child 1 1
child 1 2
child 1 3
child 1 4
child 1 5
child 1 6
DemoThread 退出
child 1 7
child 1 8
child 1 9
但是如果在一个web项目中启动DemoThread,在 DemoThread退出的时候 thdemo 没有退出
因为web项目的主进程没有退出,上面的示例能退出(也不是应为DemoThread退出)time.sleep(3)之后主进程退出了
我在我的django项目中写了一个小测试 使用 stop_thread 可以退出线程
class DemothViewSet(mixins.ListModelMixin,mixins.CreateModelMixin,mixins.UpdateModelMixin,viewsets.GenericViewSet,mixins.DestroyModelMixin):
serializer_class = DemothSerializer
def list(self, request, *args, **kwargs):
# 获取当前状态
from utils.demoth import singleton
if hasattr(singleton, "demoth"):
demoth = getattr(singleton, "demoth")
mainstatus = demoth.is_alive()
else:
mainstatus = False
if hasattr(singleton, "th"):
th = getattr(singleton, "th")
childstatus = th.is_alive()
else:
childstatus = False
return Response({"main":singleton.mainth,"child":singleton.childth,"mainstatus":mainstatus,"childstatus":childstatus})
def create(self, request, *args, **kwargs):
# todo 用于开启关闭线程
from utils.demoth import singleton
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
close = serializer.validated_data.get("close")
if close:
if hasattr(singleton,"demoth"):
demoth = getattr(singleton, "demoth")
mainstatus = demoth.is_alive()
print("mainstatus", mainstatus)
if mainstatus:
# todo 线程还在活着 手动杀掉
stop_thread(demoth)
else:
mainstatus = False
if hasattr(singleton, "th"):
demoth = getattr(singleton, "th")
childstatus = demoth.is_alive()
if childstatus:
# todo 线程还在活着 手动杀掉
stop_thread(demoth)
else:
childstatus = False
else:
demoth = DemoThread()
demoth.setDaemon(True)
demoth.start()
singleton.demoth = demoth
mainstatus = singleton.demoth.is_alive()
print("mainstatus",mainstatus)
childstatus = "Unknown"
data = serializer.data
data.update({"mainstatus":mainstatus,"childstatus":childstatus})
return Response(data, status=status.HTTP_201_CREATED,)
def update(self, request, *args, **kwargs):
# todo 用于设置DemoThread 线程 退出
from utils.demoth import singleton
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
mainth = serializer.validated_data.get("mainth")
singleton.mainth = mainth
if hasattr(singleton, "demoth"):
demoth = getattr(singleton, "demoth")
mainstatus = demoth.is_alive()
else:
mainstatus = False
if hasattr(singleton, "th"):
th = getattr(singleton, "th")
childstatus = th.is_alive()
else:
childstatus = False
return Response({"mainth":mainth,"mainstatus":mainstatus,"childstatus":childstatus})
def destroy(self, request, *args, **kwargs):
# todo 用于退出子线程
from utils.demoth import singleton
singleton.childth = 0
return Response({"childth":0})