python杀线程_Python | 杀死线程都有哪些方法?

最近业余爱好是吃了好几个月灰的树莓派,开始补全各种driver,也算是对Python的学习。写driver的过程中,第一次遇到多线程的情况。虽然没太费力就实现了想要的效果,不过还是全面学习一下比较合适。

1. 在线程中申请异常处理 和 2. 设置/重置停止符是比较常用的方法,我也用的差不多。

3.使用跟踪杀死线程)肯定是炫技的人才用的。

4. 使用多进程模块杀死线程,5.用设置为后台的方式杀死线程仅仅是为了提醒大家线程的工作原理,算是不错的知识吧。

6. 使用隐藏函数_stop()我觉得就是搞笑的。

以上是观点,以下是事实:

下文来自GeeksforGeeks:Python | Different ways to kill a Thread - GeeksforGeeks​www.geeksforgeeks.orgv2-c2feca389b6fb70d881604bc7a8d03ef_ipico.jpg

Python | Different ways to kill a Thread

通常来说,突然杀死线程是不好的编程习惯。突然杀死一个线程,可能会让一个需要恰当关闭的关键资源无法释放。但是你可能希望杀死一个线程,在过去一段时间或者某些中断发生后。以下是杀死线程的不同方法:Raising exceptions in a python thread 在线程中申请异常处理

Set/Reset stop flag 设置/重置停止符

Using traces to kill threads 使用跟踪杀死线程

Using the multiprocessing module to kill threads 使用多进程模块杀死线程

Killing Python thread by setting it as daemon 用设置为后台(daemon)的方式杀死线程

Using a hidden function _stop() 使用隐藏函数_stop()Raising exceptions in a python thread : 在线程中申请异常处理

# Python program raising exceptions in a python thread

import threading

import ctypes

import time

class thread_with_exception(threading.Thread):

def __init__(self, name):

threading.Thread.__init__(self)

self.name = name

def run(self):

# target function of the thread class

try: # 用try/finally 的方式处理exception,从而kill thread

while True:

print('running ' + self.name)

finally:

print('ended')

def get_id(self):

# returns id of the respective thread

if hasattr(self, '_thread_id'):

return self._thread_id

for id, thread in threading._active.items():

if thread is self:

return id

def raise_exception(self):

thread_id = self.get_id()

#精髓就是这句话,给线程发过去一个exceptions,线程就那边响应完就停了

res = ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id,

ctypes.py_object(SystemExit))

if res > 1:

ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id, 0)

print('Exception raise failure')

t1 = thread_with_exception('Thread 1')

t1.start()

time.sleep(2)

t1.raise_exception()

t1.join()

当我们跑上面的代码,你会注意到,只要函数raise_exception() 被调用,目标函数 run() 就结束了。这是因为只要申请exception,程序控制会跳到try代码段,然后run()函数就被终止了。在那之后,join()函数能被调用来杀死线程。如果没有函数raise_exception(),目标函数run() 就会永远跑,join()函数也没法被调用来杀死线程。

2. Set/Reset stop flag :设置/重置停止符

为了杀死一个线程,我们能声明一个停止符,并在线程中时不时的看一下这个停止符。例如:

# Python program showing how to kill threads using set/reset stop flag

import threading

import time

def run():

while True:

print('thread running')

global stop_threads

if stop_threads: #精髓在这里,这算是最直接的方法了,我也用的这个方法

break

stop_threads = False

t1 = threading.Thread(target = run)

t1.start()

time.sleep(1)

stop_threads = True

t1.join()

print('thread killed')

上面的代码中,只要全局变量stop_threads被设置,目标函数run()就停止了,然后我们就能用join()来杀掉线程t1。但是有时候我们希望能避免使用全局变量。为这种情况,我们可以为函数传入一个对象从而提供相似的功能。代码如下:

# Python program killing threads using stop flag

import threading

import time

def run(stop):

while True:

print('thread running')

if stop():

break

def main():

stop_threads = False

t1 = threading.Thread(target = run, args =(lambda : stop_threads, ))

t1.start()

time.sleep(1)

stop_threads = True

t1.join()

print('thread killed')

main()

我们为目标函数run()传入了一个终止对象stop,只要在main函数本地改变stop的值,就可以杀死线程了。

3. Using traces to kill threads : 使用跟踪杀死线程

这个方法中,我们为每一个线程都加入跟踪(traces)。每一个trace发现什么刺激或者标记的时候就会停止自身,也就杀死了对应的线程。例如:

# Python program using traces to kill threads

import sys

import trace

import threading

import time

class thread_with_trace(threading.Thread):

def __init__(self, *args, **keywords):

threading.Thread.__init__(self, *args, **keywords)

self.killed = False

def start(self):

self.__run_backup = self.run

self.run = self.__run

threading.Thread.start(self)

def __run(self):

sys.settrace(self.globaltrace) #精髓在这里,但我还没有理解为什么要这么做。。。

self.__run_backup()

self.run = self.__run_backup

def globaltrace(self, frame, event, arg):

if event == 'call':

return self.localtrace

else:

return None

def localtrace(self, frame, event, arg):

if self.killed:

if event == 'line':

raise SystemExit()

return self.localtrace

def kill(self):

self.killed = True

def func():

while True:

print('thread running')

t1 = thread_with_trace(target = func)

t1.start()

time.sleep(2)

t1.kill()

t1.join()

if not t1.isAlive():

print('thread killed')

在上面的代码中,start()被改变而加入了系统跟踪函数

4. Using the multiprocessing module to kill threads : 使用多进程模块杀死线程

Python的多进程模块允许你开启多个进程如同你开启多个线程一样。多进程模块的接口和多线程模块相似。例如,以下代码创建了3个线程从1数到9:

# Python program creating three threads

import threading

import time

# counts from 1 to 9

def func(number):

for i in range(1, 10):

time.sleep(0.01)

print('Thread ' + str(number) + ': prints ' + str(number*i))

# creates 3 threads

for i in range(0, 3):

thread = threading.Thread(target=func, args=(i,))

thread.start()

以下代码稍作改变,用进程代替了线程:

# Python program creating thread using multiprocessing module

import multiprocessing

import time

def func(number):

for i in range(1, 10):

time.sleep(0.01)

print('Processing ' + str(number) + ': prints ' + str(number*i))

for i in range(0, 3):

process = multiprocessing.Process(target=func, args=(i,))

process.start()

尽管两种模块的接口相似,但其实实现的方式非常不同。所有的线程都能分享全局变量,而进程之间完全独立。因此,杀死一个进程比之线程要安全的多。Process类提供了方法terminate()()来杀死进程。现在,让我们回到一开始的问题。对于上面的代码,如果我们想在0.03秒后杀死所有进程,我们只需要如下代码:

# Python program killing a thread using multiprocessing module

import multiprocessing

import time

def func(number):

for i in range(1, 10):

time.sleep(0.01)

print('Processing ' + str(number) + ': prints ' + str(number*i))

# list of all processes, so that they can be killed afterwards

all_processes = []

for i in range(0, 3):

process = multiprocessing.Process(target=func, args=(i,))

process.start()

all_processes.append(process)

# kill all processes after 0.03s

time.sleep(0.03)

for process in all_processes:

process.terminate() #精髓在这里

尽管这两种模块非常不同。多进程提供的功能有时和多线程非常相似,因此记得多进程有时可以作为多线程的代替,并且多进程是自带kill的。

5. Killing Python thread by setting it as daemon : 用设置为后台的方式杀死线程

后台线程是当主程序退出时杀死的线程。例如:

import threading

import time

import sys

def func():

while True:

time.sleep(0.5)

print('Thread alive, and it won't die on program termination')

t1 = threading.Thread(target=func)

t1.start()

time.sleep(2)

sys.exit()

运行程序后发现,线程t1保存活动并阻止了主程序用sys.exit()的方式退出。在Python中,任何活跃的非后台线程都会阻止主程序退出。然而,后台线程在主程序退出时就能自动杀死。为了把一个线程设置为后台,我们设置关键词daemon as True。例子如下:

# Python program killing thread using daemon

import threading

import time

import sys

def func():

while True:

time.sleep(0.5)

print('Thread alive, but it will die on program termination')

t1 = threading.Thread(target=func)

t1.daemon = True #精髓在这里

t1.start()

time.sleep(2)

sys.exit()

运行后可知,只要主程序退出,线程t1就能被杀死。在程序终止时就杀掉所有线程的情况下,这个方法非常有用。值得注意的是,在Python中,当所有非后台线程杀死后,主程序就会终止,而不管是否有后台线程任然活跃。因此,后台线程使用的资源,比如打开文件,数据库操作等,可能不能恰当的释放。这是为什么线程在Python中默认不是后台线程。强行杀死一个线程是不推荐的,除非你清楚的知道后果不会导致内存泄漏或者死锁。

6. Using a hidden function_stop():使用隐藏函数_stop()

为了杀死线程,我们可以使用隐藏函数_stop()。这个函数没有被记录在官方资料,所以有可能在下个版本就不能用了。

# Python program killing a thread using ._stop() function

import time

import threading

class MyThread(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(MyThread, self).__init__(*args, **kwargs)

self._stop = threading.Event()

# function using _stop function

def stop(self):

self._stop.set()

def stopped(self):

return self._stop.isSet()

def run(self):

while True:

if self.stopped():

return

print("Hello, world!")

time.sleep(1)

t1 = MyThread()

t1.start()

time.sleep(5)

t1.stop()

t1.join()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值