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中的CURL PycURL使用例子
Jun 01 Python
Python判断文件或文件夹是否存在的三种方法
Jul 27 Python
python 中的int()函数怎么用
Oct 17 Python
Python元组拆包和具名元组解析实例详解
Mar 26 Python
解决Python 爬虫URL中存在中文或特殊符号无法请求的问题
May 11 Python
Python实现网站表单提交和模板
Jan 15 Python
Python3批量生成带logo的二维码方法
Jun 24 Python
python打开windows应用程序的实例
Jun 28 Python
python实现文本进度条 程序进度条 加载进度条 单行刷新功能
Jul 03 Python
PyCharm设置Ipython交互环境和宏快捷键进行数据分析图文详解
Apr 23 Python
树莓派升级python的具体步骤
Jul 05 Python
有趣的二维码:使用MyQR和qrcode来制作二维码
May 10 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中HTTP方式下的Gzip压缩传输方法举偶
2007/02/15 PHP
Uchome1.2 1.5 代码学习 common.php
2009/04/24 PHP
PHP编译安装中遇到的两个错误和解决方法
2014/08/20 PHP
8个必备的PHP功能开发
2015/10/02 PHP
php中namespace use用法实例分析
2016/01/22 PHP
JS防止用户多次提交的简单代码
2013/08/01 Javascript
用js来刷新当前页面保留参数的具体实现
2013/12/23 Javascript
使用JQ来编写最基本的淡入淡出效果附演示动画
2014/10/31 Javascript
原生js实现tab选项卡切换
2020/03/23 Javascript
使用bootstrap实现多窗口和拖动效果
2016/09/22 Javascript
JS简单实现表格排序功能示例
2016/12/20 Javascript
jQueryeasyui 中如何使用datetimebox 取两个日期间相隔的天数
2017/06/13 jQuery
删除table表格行的实例讲解
2017/09/21 Javascript
jQuery AJAX 方法success()后台传来的4种数据详解
2018/08/08 jQuery
详解使用element-ui table组件的筛选功能的一个小坑
2018/11/02 Javascript
jQuery实现的五星点评功能【案例】
2019/02/18 jQuery
详解JavaScript中的强制类型转换
2019/04/15 Javascript
新手如何快速理解js异步编程
2019/06/24 Javascript
vue任意关系组件通信与跨组件监听状态vue-communication
2020/10/18 Javascript
Python实现从订阅源下载图片的方法
2015/03/11 Python
Python+OpenCV感兴趣区域ROI提取方法
2019/01/10 Python
python利用openpyxl拆分多个工作表的工作簿的方法
2019/09/27 Python
如何用canvas实现在线签名的示例代码
2018/07/10 HTML / CSS
舒适的豪华鞋:Taryn Rose
2018/05/03 全球购物
TobyDeals美国:在电子产品上获得最好的优惠和折扣
2019/08/11 全球购物
营业员个人总结的自我评价
2013/10/25 职场文书
考试违纪检讨书
2014/02/02 职场文书
《冬阳童年骆驼队》教学反思
2014/04/15 职场文书
个人三严三实对照检查材料
2014/09/25 职场文书
教师自我剖析材料范文
2014/09/30 职场文书
高校自主招生自荐信2015
2015/03/04 职场文书
医学生自荐信范文
2015/03/05 职场文书
终止劳动合同通知书
2015/04/16 职场文书
小学运动会入场口号
2015/12/24 职场文书
安全生产标语口号
2015/12/26 职场文书
分享CSS盒子模型隐藏的几种方式
2022/02/28 HTML / CSS