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实现Tab自动补全和历史命令管理的方法
Mar 12 Python
Python中获取对象信息的方法
Apr 27 Python
在Python的Django框架中获取单个对象数据的简单方法
Jul 17 Python
Python字符串拼接、截取及替换方法总结分析
Apr 13 Python
Python中使用支持向量机SVM实践
Dec 27 Python
Python使用ConfigParser模块操作配置文件的方法
Jun 29 Python
Django框架使用富文本编辑器Uedit的方法分析
Jul 31 Python
python使用tomorrow实现多线程的例子
Jul 20 Python
python定间隔取点(np.linspace)的实现
Nov 27 Python
Django+boostrap 美化admin后台的操作
Mar 11 Python
解决paramiko执行命令超时的问题
Apr 16 Python
Python自动化操作实现图例绘制
Jul 09 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正则+Snoopy抓取框架实现的抓取淘宝店信誉功能实例
2017/05/17 PHP
php支付宝APP支付功能
2020/07/29 PHP
thinkPHP5.0框架验证码调用及点击图片刷新简单实现方法
2018/09/07 PHP
JavaScript 浏览器验证代码(来自discuz)
2010/07/17 Javascript
疯狂Jquery第一天(Jquery学习笔记)
2012/05/11 Javascript
使用JavaScript获取电池状态的方法
2014/05/03 Javascript
clipboard.js无需Flash无需依赖任何JS库实现文本复制与剪切
2015/10/10 Javascript
BootStrap 附加导航组件
2016/07/22 Javascript
浅谈jQuery中Ajax事件beforesend及各参数含义
2016/12/03 Javascript
浅谈javascript alert和confirm的美化
2016/12/15 Javascript
详解nodejs 文本操作模块-fs模块(一)
2016/12/22 NodeJs
vue组件生命周期详解
2017/11/07 Javascript
搭建vue开发环境
2018/07/19 Javascript
Vue.js中对css的操作(修改)具体方式详解
2018/10/30 Javascript
jquery分页优化操作实例分析
2019/08/23 jQuery
Jquery ajax书写方法代码实例解析
2020/06/12 jQuery
JS轮播图的实现方法2
2020/08/25 Javascript
详解nginx配置vue h5 history去除#号
2020/11/09 Javascript
[49:17]DOTA2-DPC中国联赛 正赛 Phoenix vs Dynasty BO3 第三场 1月26日
2021/03/11 DOTA
跟老齐学Python之集成开发环境(IDE)
2014/09/12 Python
听歌识曲--用python实现一个音乐检索器的功能
2016/11/15 Python
Python并行分布式框架Celery详解
2018/10/15 Python
Python中的取模运算方法
2018/11/10 Python
在Pandas中给多层索引降级的方法
2018/11/16 Python
Pytorch之卷积层的使用详解
2019/12/31 Python
Python基于codecs模块实现文件读写案例解析
2020/05/11 Python
Python CSS选择器爬取京东网商品信息过程解析
2020/06/01 Python
在Keras中利用np.random.shuffle()打乱数据集实例
2020/06/15 Python
英语系本科生个人求职信
2013/09/21 职场文书
2014年党员公开承诺书范文
2014/03/28 职场文书
2014年教研活动总结范文
2014/04/26 职场文书
世博会口号
2014/06/20 职场文书
道路运输企业安全生产责任书
2014/07/28 职场文书
八项规定对照检查材料
2014/08/31 职场文书
会计岗位工作总结
2015/08/12 职场文书
幼儿园大班教育随笔
2015/08/14 职场文书