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基于windows平台锁定键盘输入的方法
Mar 05 Python
python切片及sys.argv[]用法详解
May 25 Python
一百多行python代码实现抢票助手
Sep 25 Python
flask-restful使用总结
Dec 04 Python
200行python代码实现2048游戏
Jul 17 Python
Python 3.8正式发布,来尝鲜这些新特性吧
Oct 15 Python
Python列表元素常见操作简单示例
Oct 25 Python
python3 实现调用串口功能
Dec 26 Python
Python3.6 中的pyinstaller安装和使用教程
Mar 16 Python
使用keras实现densenet和Xception的模型融合
May 23 Python
django rest framework 自定义返回方式
Jul 12 Python
用python制作个音乐下载器
Jan 30 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
萌王史莱姆”萌王性别尴尬!那“萌战”归女组还是男?
2018/12/17 日漫
linux php mysql数据库备份实现代码
2009/03/10 PHP
PHP实现域名whois查询的代码(数据源万网、新网)
2010/02/22 PHP
PHP版QQ互联OAuth示例代码分享
2015/07/05 PHP
浅谈PHP中其他类型转化为Bool类型
2016/03/28 PHP
PhpStorm本地断点调试的方法步骤
2018/05/21 PHP
PHP验证类的封装与使用方法详解
2019/01/10 PHP
关于URL中的特殊符号使用介绍
2011/11/03 Javascript
jQuery源码分析-03构造jQuery对象-源码结构和核心函数
2011/11/14 Javascript
node.js中的http.createClient方法使用说明
2014/12/15 Javascript
JS实现单击输入框弹出选择框效果完整实例
2015/12/14 Javascript
js父页面中使用子页面的方法
2016/01/09 Javascript
AngularJS 中使用Swiper制作滚动图不能滑动的解决方法
2016/11/15 Javascript
微信小程序开发实战教程之手势解锁
2016/11/18 Javascript
bootstrap table实现单击单元格可编辑功能
2017/03/28 Javascript
在vue-cli中组件通信的方法
2017/12/16 Javascript
重新认识vue之事件阻止冒泡的实现
2018/08/02 Javascript
angularJs中ng-model-options设置数据同步的方法
2018/09/30 Javascript
简单说说angular.json文件的使用
2018/10/29 Javascript
JS中min函数实例讲解
2019/02/18 Javascript
JS/jQuery实现获取时间的方法及常用类完整示例
2019/03/07 jQuery
详解Node.js一行命令上传本地文件到服务器
2019/04/22 Javascript
elementUI 动态生成几行几列的方法示例
2019/07/11 Javascript
python列表生成式与列表生成器的使用
2018/02/23 Python
python爬取抖音视频的实例分析
2021/01/19 Python
What is EJB
2016/07/22 面试题
初中数学教学反思
2014/01/16 职场文书
四年级数学教学反思
2014/02/02 职场文书
好的促销活动方案
2014/08/21 职场文书
店铺转让协议书(2014版)
2014/09/23 职场文书
2014最新党员批评与自我批评材料
2014/09/24 职场文书
公安机关纪律作风整顿个人剖析材料材料
2014/10/10 职场文书
2015年度护士个人工作总结
2015/04/09 职场文书
一篇文章弄懂MySQL查询语句的执行过程
2021/05/07 MySQL
SQL注入篇学习之盲注/宽字节注入
2022/03/03 MySQL
Go Grpc Gateway兼容HTTP协议文档自动生成网关
2022/06/16 Golang