- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章不要用强制方法杀掉python线程由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
前言
不要试图用强制方法杀掉一个python线程,这从服务设计上就存在不合理性。 多线程本用来任务的协作并发,如果你使用强制手段干掉线程,那么很大几率出现意想不到的bug。 请记住一点,锁资源不会因为线程退出而释放锁资源 ! 。
我们可以举出两个常见的例子:
1. 有个A线程拿到了锁,因为他是被强制干掉的,没能及时的release()释放锁资源,那么导致所有的线程获取资源是都被阻塞下去,这就是典型的死锁场景.
2.在常见的生产消费者的场景下,消费者从任务队列获取任务,但是被干掉后没有把正在做的任务丢回队列中,那么这就造成了数据丢失.
下面是java和python终止线程的方法
java有三种方法可以使终止线程:
1. 使用退出标志,使线程正常退出,也就是当run方法完成后线程终止。 2. 使用stop方法强行终止线程(不推荐使用,因为stop和suspend、resume一样,也可能发生不可预料的结果)。 3. 使用interrupt方法中断线程.
python可以有两种方法:
1. 退出标记 2. 使用ctypes强行杀掉线程 。
不管是python还是java环境下,理想的停止退出线程方法是 让线程自个自杀,所谓的线程自杀就是 你给他一个标志位,他退出线程.
下面我们会采用多种方法来测试 停止python线程的异常情况。我们查看一个进程所有的执行线程, 进程是用过掌控资源,线程是用作调度单元,进程要被调度执行必须要有一个线程,默认的线程和进程的pid一样的.
1
2
3
4
5
6
|
ps
-
mp
31449
-
o THREAD,tid
USER
%
CPU PRI SCNT WCHAN USER SYSTEM TID
root
0.0
-
-
-
-
-
-
root
0.0
19
-
poll_s
-
-
31449
root
0.0
19
-
poll_s
-
-
31450
|
获取到了进程所有的线程后,通过strace得知 31450 是需要我们kill的线程id,当我们kill的时候,会出现整个进程都崩溃的情况。 在多线程环境下,产生的信号是传递给整个进程的,一般而言,所有线程都有机会收到这个信号,进程在收到信号的的线程上下文执行信号处理函数,具体是哪个线程执行的难以获知。也就是说,信号会随机发个该进程的一个线程.
1
2
3
4
5
6
7
|
strace
-
p <span style
=
"font-size:14px;line-height:21px;"
>
31450
<
/
span> Process <span style
=
"font-size:14px;line-height:21px;"
>
31450
<
/
span> attached
-
interrupt to quit
select(
0
, NULL, NULL, NULL, {
0
,
320326
})
=
0
(Timeout)
select(
0
, NULL, NULL, NULL, {
1
,
0
})
=
0
(Timeout)
select(
0
, NULL, NULL, NULL, {
1
,
0
})
=
0
(Timeout)
select(
0
, NULL, NULL, NULL, {
1
,
0
})
=
? ERESTARTNOHAND (To be restarted)
-
-
-
SIGTERM (Terminated) @
0
(
0
)
-
-
-
Process <span style
=
"font-size:14px;line-height:21px;"
>
31450
<
/
span> detached
|
上面出现的问题其实跟pthread的说明是一致的。当我们在python代码里加入 signal 信号处理函数后,回调函数可以防止整个进程的退出,那么问题来了,通过信号函数不能识别你要干掉哪一个线程,也就是说,不能精准的干掉某个线程。你虽然把信号发给31450线程id,但是信号受理人是所属进程的任何一个,另外传给信号处理函数的参数只有信号数和信号stack而已,可有可无的.
加了信号处理后,不会退出进程 。
1
2
3
4
5
6
|
select(
0
, NULL, NULL, NULL, {
1
,
0
})
=
0
(Timeout)
select(
0
, NULL, NULL, NULL, {
1
,
0
})
=
? ERESTARTNOHAND (To be restarted)
-
-
-
SIGTERM (Terminated) @
0
(
0
)
-
-
-
rt_sigreturn(
0xffffffff
)
=
-
1
EINTR (Interrupted system call)
select(
0
, NULL, NULL, NULL, {
1
,
0
})
=
0
(Timeout)
select(
0
, NULL, NULL, NULL, {
1
,
0
})
=
0
(Timeout)
|
如果想从外部通知杀掉某个线程,那么可以构建使用rpc服务,或者别的方式通信,signal信号不可以,因为无法无法传递更多的信息.
python的线程不是模拟的,是真实的内核线程,内核调用pthread方法,但Python上层没有提供关闭线程的方法,这就需要我们自己把握了。强烈推荐使用 event 或者 自定义标志位的方法, 如果非要强制杀掉线程,那么可以用python ctypes PyThreadState SetAsyncExc 方法强制退出,这样对于运行的python服务没有什么影响.
该函数的实现原理比较简单,其实也是在python虚拟机里做个标示位,然后由虚拟机运行一个异常来取消线程,虚拟机会帮你做好try cache。 切记不要在外部杀掉python的某个线程,虽然你能通过ctypes找到线程id,但是你直接kill会干掉整个进程的.
下面的代码是 用ctypes 杀掉线程的样例,不推荐使用,因为太粗暴了. 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
import
ctypes
def
terminate_thread(thread):
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
:
ctypes.pythonapi.PyThreadState_SetAsyncExc(thread.ident,
None
)
raise
SystemError(
"PyThreadState_SetAsyncExc failed"
)
|
咱们简单look一下PyThreadState源代码,总而言之触发线程的异常模式。 有兴趣的人可以阅读 python pystate.c 的设计,配合着youtube的一些视频分享.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
int
PyThreadState_SetAsyncExc(
long
id
, PyObject
*
exc) {
PyInterpreterState
*
interp
=
GET_INTERP_STATE();
...
HEAD_LOCK();
for
(p
=
interp
-
>tstate_head; p !
=
NULL; p
=
p
-
>
next
) {
if
(p
-
>thread_id
=
=
id
) {
从链表里找到线程的
id
,避免死锁,我们需要释放head_mutex。
PyObject
*
old_exc
=
p
-
>async_exc;
Py_XINCREF(exc);
#增加该对象的引用数
p
-
>async_exc
=
exc;
# 更为exc模式
HEAD_UNLOCK();
Py_XDECREF(old_exc);
# 因为要取消,当然也就递减引用
...
return
1
;
#销毁线程成功
}
}
HEAD_UNLOCK();
return
0
;
}
|
原生posix pthread 可以使用 ptread_cancel(tid) 在主线程中结束子线程。但是 Python 的线程库不支持这样做,理由是我们不应该强制地结束一个线程,这样会带来很多隐患,应该让该线程自己结束自己。所以在 Python 中,推荐的方法是在子线程中循环判断一个标志位,在主线程中改变该标志位,子线程读到标志位改变,就结束自己.
类似这个逻辑
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
def
consumer_threading():
t1_stop
=
threading.Event()
t1
=
threading.Thread(target
=
thread1, args
=
(
1
, t1_stop))
t2_stop
=
threading.Event()
t2
=
threading.Thread(target
=
thread2, args
=
(
2
, t2_stop))
time.sleep(duration)
#stop the thread2
t2_stop.
set
()
def
thread1(arg1, stop_event):
while
(
not
stop_event.is_set()):
#similar to time.sleep()
stop_event.wait(time)
pass
def
thread2(arg1, stop_event):
while
(
not
stop_event.is_set()):
stop_event.wait(time)
pass
|
简单的总结,虽然我们可以用ctypes里的pystats来控制线程,但这种粗暴中断线程的方法是不合理的。 请选用 自杀模式 !如果你的线程正在发生io阻塞,而不能判断事件怎么办? 你的程序需要做优化了,最少在网络io层需要有主动的timeout,避免一直的阻塞下去.
最后此篇关于不要用强制方法杀掉python线程的文章就讲到这里了,如果你想了解更多关于不要用强制方法杀掉python线程的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我将 Bootstrap 与 css 和 java 脚本结合使用。在不影响前端代码的情况下,我真的很难在css中绘制这个背景。在许多问题中,人们将宽度和高度设置为 0%。但是由于我的导航栏,我不能使用
我正在用 c 编写一个程序来读取文件的内容。代码如下: #include void main() { char line[90]; while(scanf("%79[^\
我想使用 javascript 获取矩阵数组的所有对 Angular 线。假设输入输出如下: input = [ [1,2,3], [4,5,6], [7,8,9], ] output =
可以用pdfmake绘制lines,circles和other shapes吗?如果是,是否有documentation或样本?我想用jsPDF替换pdfmake。 最佳答案 是的,有可能。 pdfm
我有一个小svg小部件,其目的是显示角度列表(参见图片)。 现在,角度是线元素,仅具有笔触,没有填充。但是现在我想使用一种“内部填充”颜色和一种“笔触/边框”颜色。我猜想line元素不能解决这个问题,
我正在为带有三角对象的 3D 场景编写一个非常基本的光线转换器,一切都工作正常,直到我决定尝试从场景原点 (0/0/0) 以外的点转换光线。 但是,当我将光线原点更改为 (0/1/0) 时,相交测试突
这个问题已经有答案了: Why do people write "#!/usr/bin/env python" on the first line of a Python script? (22 个回
如何使用大约 50 个星号 * 并使用 for 循环绘制一条水平线?当我尝试这样做时,结果是垂直(而不是水平)列出 50 个星号。 public void drawAstline() { f
这是一个让球以对角线方式下降的 UI,但球保持静止;线程似乎无法正常工作。你能告诉我如何让球移动吗? 请下载一个球并更改目录,以便程序可以找到您的球的分配位置。没有必要下载足球场,但如果您愿意,也可以
我在我的一个项目中使用 Jmeter 和 Ant,当我们生成报告时,它会在报告中显示 URL、#Samples、失败、成功率、平均时间、最短时间、最长时间。 我也想在报告中包含 90% 的时间线。 现
我有一个不寻常的问题,希望有人能帮助我。我想用 Canvas (android) 画一条 Swing 或波浪线,但我不知道该怎么做。它将成为蝌蚪的尾部,所以理想情况下我希望它的形状更像三角形,一端更大
这个问题已经有答案了: Checking Collision of Shapes with JavaFX (1 个回答) 已关闭 8 年前。 我正在使用 JavaFx 8 库。 我的任务很简单:我想检
如何按编号的百分比拆分文件。行数? 假设我想将我的文件分成 3 个部分(60%/20%/20% 部分),我可以手动执行此操作,-_-: $ wc -l brown.txt 57339 brown.tx
我正在努力实现这样的目标: 但这就是我设法做到的。 你能帮我实现预期的结果吗? 更新: 如果我删除 bootstrap.css 依赖项,问题就会消失。我怎样才能让它与 Bootstrap 一起工作?
我目前正在构建一个网站,但遇到了 transform: scale 的问题。我有一个按钮,当用户将鼠标悬停在它上面时,会发生两件事: 背景以对 Angular 线“扫过” 按钮标签颜色改变 按钮稍微变
我需要使用直线和仿射变换绘制大量数据点的图形(缩放图形以适合 View )。 目前,我正在使用 NSBezierPath,但我认为它效率很低(因为点在绘制之前被复制到贝塞尔路径)。通过将我的数据切割成
我正在使用基于 SVM 分类的 HOG 特征检测器。我可以成功提取车牌,但提取的车牌除了车牌号外还有一些不必要的像素/线。我的图像处理流程如下: 在灰度图像上应用 HOG 检测器 裁剪检测到的区域 调
我有以下图片: 我想填充它的轮廓(即我想在这张图片中填充线条)。 我尝试了形态学闭合,但使用大小为 3x3 的矩形内核和 10 迭代并没有填满整个边界。我还尝试了一个 21x21 内核和 1 迭代,但
我必须找到一种算法,可以找到两组数组之间的交集总数,而其中一个数组已排序。 举个例子,我们有这两个数组,我们向相应的数字画直线。 这两个数组为我们提供了总共 7 个交集。 有什么样的算法可以帮助我解决
简单地说 - 我想使用透视投影从近裁剪平面绘制一条射线/线到远裁剪平面。我有我认为是使用各种 OpenGL/图形编程指南中描述的方法通过单击鼠标生成的正确标准化的世界坐标。 我遇到的问题是我的光线似乎
我是一名优秀的程序员,十分优秀!