Python中用Ctrl+C终止多线程程序的问题解决


Posted in Python onMarch 30, 2013
#!/bin/env python
 # -*- coding: utf-8 -*-
 #filename: peartest.py import threading, signal
 is_exit = False
 def doStress(i, cc):
     global is_exit
     idx = i
     while not is_exit:
         if (idx < 10000000):
             print "thread[%d]: idx=%d"%(i, idx)
             idx = idx + cc
         else:
             break
     print "thread[%d] complete."%i
 def handler(signum, frame):
     global is_exit
     is_exit = True
     print "receive a signal %d, is_exit = %d"%(signum, is_exit)
 if __name__ == "__main__":
     signal.signal(signal.SIGINT, handler)
     signal.signal(signal.SIGTERM, handler)
     cc = 5
     for i in range(cc):
         t = threading.Thread(target=doStress, args=(i,cc))
         t.start()

上面是一个模拟程序,并不真正向服务发送请求,而代之以在一千万以内,每个线程每隔并发数个(cc个)打印一个整数。很明显,当所有线程都完成自己的任务后,进程会正常退出。但如果我们中途想退出(试想一个压力测试程序,在中途已经发现了问题,需要停止测试),该肿么办?你当然可以用ps查找到进程号,然后kill -9杀掉,但这样太繁琐了,捕捉Ctrl+C是最自然的想法。上面示例程序中已经捕捉了这个信号,并修改全局变量is_exit,线程中会检测这个变量,及时退出。

但事实上这个程序并不work,当你按下Ctrl+C时,程序照常运行,并无任何响应。网上搜了一些资料,明白是python的子线程如果不是daemon的话,主线程是不能响应任何中断的。但设为daemon后主线程会随之退出,接着整个进程很快就退出了,所以还需要在主线程中检测各个子线程的状态,直到所有子线程退出后自己才退出,因此上例29行之后的代码可以修改为:

threads=[]
     for i in range(cc):
         t = threading.Thread(target=doStress, args=(i, cc))
         t.setDaemon(True)
         threads.append(t)
         t.start()
     for i in range(cc):
         threads[i].join()

重新试一下,问题依然没有解决,进程还是没有响应Ctrl+C,这是因为join()函数同样会waiting在一个锁上,使主线程无法捕获信号。因此继续修改,调用线程的isAlive()函数判断线程是否完成:

while 1:
         alive = False
         for i in range(cc):
             alive = alive or threads[i].isAlive()
         if not alive:
             break

这样修改后,程序完全按照预想运行了:可以顺利的打印每个线程应该打印的所有数字,也可以中途用Ctrl+C终结整个进程。完整的代码如下:

#!/bin/env python
 # -*- coding: utf-8 -*-
 #filename: peartest.py import threading, signal
 is_exit = False
 def doStress(i, cc):
     global is_exit
     idx = i
     while not is_exit:
         if (idx < 10000000):
             print "thread[%d]: idx=%d"%(i, idx)
             idx = idx + cc
         else:
             break
     if is_exit:
         print "receive a signal to exit, thread[%d] stop."%i
     else:
         print "thread[%d] complete."%i
 def handler(signum, frame):
     global is_exit
     is_exit = True
     print "receive a signal %d, is_exit = %d"%(signum, is_exit)
 if __name__ == "__main__":
     signal.signal(signal.SIGINT, handler)
     signal.signal(signal.SIGTERM, handler)
     cc = 5
     threads = []
     for i in range(cc):
         t = threading.Thread(target=doStress, args=(i,cc))
         t.setDaemon(True)
         threads.append(t)
         t.start()
     while 1:
         alive = False
         for i in range(cc):
             alive = alive or threads[i].isAlive()
         if not alive:
             break

其实,如果用python写一个服务,也需要这样,因为负责服务的那个线程是永远在那里接收请求的,不会退出,而如果你想用Ctrl+C杀死整个服务,跟上面的压力测试程序是一个道理。总结一下,python多线程中要响应Ctrl+C的信号以杀死整个进程,需要:

1.把所有子线程设为Daemon;
2.使用isAlive()函数判断所有子线程是否完成,而不是在主线程中用join()函数等待完成;
3.写一个响应Ctrl+C信号的函数,修改全局变量,使得各子线程能够检测到,并正常退出。

Python 相关文章推荐
python实现简单ftp客户端的方法
Jun 28 Python
python批量提取word内信息
Aug 09 Python
尝试使用Python多线程抓取代理服务器IP地址的示例
Nov 09 Python
Windows下Anaconda2安装NLTK教程
Sep 19 Python
python制作图片缩略图
Apr 30 Python
python 求一个列表中所有元素的乘积实例
Jun 11 Python
对Python的交互模式和直接运行.py文件的区别详解
Jun 29 Python
python+Django实现防止SQL注入的办法
Oct 31 Python
Python利用matplotlib绘制约数个数统计图示例
Nov 26 Python
解决pycharm启动后总是不停的updating indices...indexing的问题
Nov 27 Python
python3利用Axes3D库画3D模型图
Mar 25 Python
Django Admin后台模型列表页面如何添加自定义操作按钮
Nov 11 Python
python利用hook技术破解https的实例代码
Mar 25 #Python
利用python获得时间的实例说明
Mar 25 #Python
python 将字符串转换成字典dict
Mar 24 #Python
使用python提取html文件中的特定数据的实现代码
Mar 24 #Python
python 切片和range()用法说明
Mar 24 #Python
python list中append()与extend()用法分享
Mar 24 #Python
python del()函数用法
Mar 24 #Python
You might like
基于php中使用excel的简单介绍
2013/08/02 PHP
PHP搭建大文件切割分块上传功能示例
2017/01/04 PHP
微信推送功能实现方式图文详解
2019/07/12 PHP
用javascript getComputedStyle获取和设置style的原理
2008/10/10 Javascript
jQuery实现点击标题输入详细信息
2013/04/16 Javascript
JS复制内容到剪切板的实例代码(兼容IE与火狐)
2013/11/19 Javascript
javascript四舍五入函数代码分享(保留后几位)
2013/12/10 Javascript
jquery ajax,ashx,json的用法总结
2014/02/12 Javascript
javascript轻量级库createjs使用Easel实现拖拽效果
2016/02/19 Javascript
jQuery日历插件datepicker用法详解
2016/03/03 Javascript
JS代码实现百度地图 画圆 删除标注
2016/10/12 Javascript
百度多文件异步上传控件webuploader基本用法解析
2016/11/07 Javascript
JavaScript 详解预编译原理
2017/01/22 Javascript
Node.js 8 中的 util.promisify的详解
2017/06/12 Javascript
详解webpack+vue-cli项目打包技巧
2017/06/17 Javascript
vue2.x 通过后端接口代理,获取qq音乐api的数据示例
2019/10/30 Javascript
微信小程序对图片进行canvas压缩的方法示例详解
2020/11/12 Javascript
[49:08]Secret vs VP 2018国际邀请赛小组赛BO2 第一场 8.17
2018/08/20 DOTA
[06:07]DOTA2-DPC中国联赛 正赛 Ehome vs VG 选手采访
2021/03/11 DOTA
网站渗透常用Python小脚本查询同ip网站
2017/05/08 Python
通过Python实现自动填写调查问卷
2017/09/06 Python
Pandas:Series和DataFrame删除指定轴上数据的方法
2018/11/10 Python
django 数据库连接模块解析及简单长连接改造方法
2019/08/29 Python
django模型类中,null=True,blank=True用法说明
2020/07/09 Python
html5指南-2.如何操作document metadata
2013/01/07 HTML / CSS
HTML5中5个简单实用的API
2014/04/28 HTML / CSS
HTML5 3D衣服摇摆动画特效
2016/03/17 HTML / CSS
最耐用行李箱,一箱永流传:Briggs & Riley(全球终身保修)
2017/12/07 全球购物
写clone()方法时,通常都有一行代码,是什么?
2012/10/31 面试题
小班秋游活动方案
2014/02/22 职场文书
面试复试通知单
2015/04/24 职场文书
2015年度信用社工作总结
2015/05/04 职场文书
课改心得体会范文
2016/01/25 职场文书
刚学完怎么用Python实现定时任务,转头就跑去撩妹!
2021/06/05 Python
python中的mysql数据库LIKE操作符详解
2021/07/01 MySQL
升级 Win11 还是坚守 Win10?微软 Win11 新系统缺失功能大盘点
2022/04/05 数码科技