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 实现文件的全备份和差异备份详解
Dec 27 Python
python之从文件读取数据到list的实例讲解
Apr 19 Python
python实现从pdf文件中提取文本,并自动翻译的方法
Nov 28 Python
PyQt5实现简单数据标注工具
Mar 18 Python
Python操作rabbitMQ的示例代码
Mar 19 Python
Python Django 封装分页成通用的模块详解
Aug 21 Python
ubuntu上安装python的实例方法
Sep 30 Python
python实现将视频按帧读取到自定义目录
Dec 10 Python
Pytorch中.new()的作用详解
Feb 18 Python
Python实现企业微信机器人每天定时发消息实例
Feb 25 Python
python3 自动打印出最新版本执行的mysql2redis实例
Apr 09 Python
浅谈Python中的生成器和迭代器
Jun 19 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
ThinkPHP字符串函数及常用函数汇总
2014/07/18 PHP
php实现的简单检验登陆类
2015/06/18 PHP
php版微信公众号接口实现发红包的方法
2016/10/14 PHP
php 删除指定文件夹的实例讲解
2017/07/25 PHP
阿里云Win2016安装Apache和PHP环境图文教程
2018/03/11 PHP
JavaScript词法作用域与调用对象深入理解
2012/11/29 Javascript
JS实现仿百度输入框自动匹配功能的示例代码
2014/02/19 Javascript
js的touch事件的实际引用
2014/10/13 Javascript
js闭包引起的事件注册问题介绍
2016/03/29 Javascript
用file标签实现多图文件上传预览
2017/02/14 Javascript
javascript 中的继承实例详解
2017/05/05 Javascript
详解vue嵌套路由-query传递参数
2017/05/23 Javascript
微信小程序 生命周期函数详解
2017/05/24 Javascript
vue-cli配置环境变量的方法
2018/07/09 Javascript
详解Vue demo实现商品列表的展示
2019/05/07 Javascript
手把手带你入门微信小程序新框架Kbone的使用
2020/02/25 Javascript
在Python编程过程中用单元测试法调试代码的介绍
2015/04/02 Python
Django中使用group_by的方法
2015/05/26 Python
解决安装python库时windows error5 报错的问题
2018/10/21 Python
为何人工智能(AI)首选Python?读完这篇文章你就知道了(推荐)
2019/04/06 Python
Flask 上传自定义头像的实例详解
2020/01/09 Python
Python+OpenCV图像处理——实现轮廓发现
2020/10/23 Python
床上用品全球在线购物:BeddingInn
2016/12/18 全球购物
什么时候用assert
2015/05/08 面试题
计算机专业个人求职自荐信
2013/09/21 职场文书
《鱼游到了纸上》教学反思
2014/02/20 职场文书
给老婆的保证书范文
2014/04/28 职场文书
浪漫婚礼主题活动策划方案
2014/09/15 职场文书
自习课吵闹检讨书范文
2014/09/26 职场文书
农村婚庆主持词
2015/06/29 职场文书
岗位聘任协议书
2015/09/21 职场文书
会计做账心得体会
2016/01/22 职场文书
2016年优秀共产党员先进事迹材料
2016/02/29 职场文书
python如何利用cv2模块读取显示保存图片
2021/06/04 Python
vue的项目如何打包上线
2022/04/13 Vue.js
在Oracle表中进行关键词搜索的过程
2022/06/10 Oracle