python多线程ctrl-c退出问题
场景:
经常会遇到下述问题:很多io busy的应用采取多线程的方式来解决,但这时候会发现python命令行不响应ctrl-c 了,而对应的java代码则没有问题:
- public class Test {
- public static void main(String[] args) throws Exception {
- new Thread(new Runnable() {
- public void run() {
- long start = System.currentTimeMillis();
- while (true) {
- try {
- Thread.sleep(1000);
- } catch (Exception e) {
- }
- System.out.println(System.currentTimeMillis());
- if (System.currentTimeMillis() - start > 1000 * 100) break;
- }
- }
- }).start();
- }
- }
java Test
ctrl-c则会结束程序
而对应的python代码:
- # -*- coding: utf-8 -*-
- import time
- import threading
- start=time.time()
- def foreverLoop():
- start=time.time()
- while 1:
- time.sleep(1)
- print time.time()
- if time.time()-start>100:
- break
- thread_=threading.Thread(target=foreverLoop)
- #thread_.setDaemon(True)
- thread_.start()
python p.py
后ctrl-c则完全不起作用了。
不成熟的分析:
首先单单设置 daemon 为 true 肯定不行,就不解释了。当daemon为 false 时,导入python线程库后实际上,threading会在主线程执行完毕后,检查是否有不是 daemon 的线程,有的化就wait,等待线程结束了,在主线程等待期间,所有发送到主线程的信号也会被阻测,可以在上述代码加入signal模块验证一下:
- def sigint_handler(signum,frame):
- print "main-thread exit"
- sys.exit()
- signal.signal(signal.SIGINT,sigint_handler)
在100秒内按下ctrl-c没有反应,只有当子线程结束后才会出现打印 "main-thread exit",可见 ctrl-c被阻测了
threading 中在主线程结束时进行的操作:
- _shutdown = _MainThread()._exitfunc
- def _exitfunc(self):
- self._Thread__stop()
- t = _pickSomeNonDaemonThread()
- if t:
- if __debug__:
- self._note("%s: waiting for other threads", self)
- while t:
- t.join()
- t = _pickSomeNonDaemonThread()
- if __debug__:
- self._note("%s: exiting", self)
- self._Thread__delete()
对所有的非daemon线程进行join等待,其中join中可自行察看源码,又调用了wait,同上文分析 ,主线程等待到了一把锁上。
不成熟的解决:
只能把线程设成daemon才能让主线程不等待,能够接受ctrl-c信号,但是又不能让子线程立即结束,那么只能采用传统的轮询方法了,采用sleep间歇省点cpu吧:
- # -*- coding: utf-8 -*-
- import time,signal,traceback
- import sys
- import threading
- start=time.time()
- def foreverLoop():
- start=time.time()
- while 1:
- time.sleep(1)
- print time.time()
- if time.time()-start>5:
- break
- thread_=threading.Thread(target=foreverLoop)
- thread_.setDaemon(True)
- thread_.start()
- #主线程wait住了,不能接受信号了
- #thread_.join()
- def _exitCheckfunc():
- print "ok"
- try:
- while 1:
- alive=False
- if thread_.isAlive():
- alive=True
- if not alive:
- break
- time.sleep(1)
- #为了使得统计时间能够运行,要捕捉 KeyboardInterrupt :ctrl-c
- except KeyboardInterrupt, e:
- traceback.print_exc()
- print "consume time :",time.time()-start
- threading._shutdown=_exitCheckfunc
缺点:轮询总会浪费点cpu资源,以及battery.
有更好的解决方案敬请提出。
ps1: 进程监控解决方案 :
用另外一个进程来接受信号后杀掉执行任务进程,牛
- # -*- coding: utf-8 -*-
- import time,signal,traceback,os
- import sys
- import threading
- start=time.time()
- def foreverLoop():
- start=time.time()
- while 1:
- time.sleep(1)
- print time.time()
- if time.time()-start>5:
- break
- class Watcher:
- """this class solves two problems with multithreaded
- programs in Python, (1) a signal might be delivered
- to any thread (which is just a malfeature) and (2) if
- the thread that gets the signal is waiting, the signal
- is ignored (which is a bug).
- The watcher is a concurrent process (not thread) that
- waits for a signal and the process that contains the
- threads. See Appendix A of The Little Book of Semaphores.
- http://greenteapress.com/semaphores/
- I have only tested this on Linux. I would expect it to
- work on the Macintosh and not work on Windows.
- """
- def __init__(self):
- """ Creates a child thread, which returns. The parent
- thread waits for a KeyboardInterrupt and then kills
- the child thread.
- """
- self.child = os.fork()
- if self.child == 0:
- return
- else:
- self.watch()
- def watch(self):
- try:
- os.wait()
- except KeyboardInterrupt:
- # I put the capital B in KeyBoardInterrupt so I can
- # tell when the Watcher gets the SIGINT
- print 'KeyBoardInterrupt'
- self.kill()
- sys.exit()
- def kill(self):
- try:
- os.kill(self.child, signal.SIGKILL)
- except OSError: pass
- Watcher()
- thread_=threading.Thread(target=foreverLoop)
- thread_.start()
注意 watch()一定要放在线程创建前,原因未知。。。。,否则立刻就结束
python多线程ctrl-c退出问题的更多相关文章
- python多线程threading
本文通过 4个example 介绍python中多线程package —— threading的常用用法, 包括调用多线程, 同步队列类Queue, Ctrl+c结束多线程. example1. 调用 ...
- [转]python 多线程threading简单分析
多线程和多进程是什么自行google补脑 对于python 多线程的理解,我花了很长时间,搜索的大部份文章都不够通俗易懂.所以,这里力图用简单的例子,让你对多线程有个初步的认识. 单线程 在好些年前的 ...
- python多线程学习记录
1.多线程的创建 import threading t = t.theading.Thread(target, args--) t.SetDeamon(True)//设置为守护进程 t.start() ...
- python多线程编程
Python多线程编程中常用方法: 1.join()方法:如果一个线程或者在函数执行的过程中调用另一个线程,并且希望待其完成操作后才能执行,那么在调用线程的时就可以使用被调线程的join方法join( ...
- Python 多线程教程:并发与并行
转载于: https://my.oschina.net/leejun2005/blog/398826 在批评Python的讨论中,常常说起Python多线程是多么的难用.还有人对 global int ...
- python 多线程就这么简单(转)
多线程和多进程是什么自行google补脑 对于python 多线程的理解,我花了很长时间,搜索的大部份文章都不够通俗易懂.所以,这里力图用简单的例子,让你对多线程有个初步的认识. 单线程 在好些年前的 ...
- 【python,threading】python多线程
使用多线程的方式 1. 函数式:使用threading模块threading.Thread(e.g target name parameters) import time,threading def ...
- Python多线程和Python的锁
Python多线程 Python中实现多线程有两种方式,一种基于_thread模块(在Python2.x版本中为thread模块,没有下划线)的start_new_thread()函数,另一种基于th ...
- 【跟我一起学Python吧】Python 多线程
其实自我感觉Python的多线程很类似于Java的多线程机制,但是比JAVA的多线程更灵活.在早期的Python多线程实现中,采用了thread模块.例如: from time import ctim ...
- 关于python多线程编程中join()和setDaemon()的一点儿探究
关于python多线程编程中join()和setDaemon()的用法,这两天我看网上的资料看得头晕脑涨也没看懂,干脆就做一个实验来看看吧. 首先是编写实验的基础代码,创建一个名为MyThread的 ...
随机推荐
- lintcode: 有效的括号序列
题目: 有效的括号序列 给定一个字符串所表示的括号序列,包含以下字符: '(', ')', '{', '}', '[' and']', 判定是否是有效的括号序列. 样例 括号必须依照 "() ...
- 【mongoDB中级篇②】索引与expain
索引的操作 数据库百分之八十的工作基本上都是查询,而索引能帮我们更快的查询到想要的数据.但是其降低了数据的写入速度,所以要权衡常用的查询字段,不必在太多字段上建立索引. 在mongoDB中默认是用bt ...
- Apache与Tomcat整合
Apache与Tomcat整合 一 Apache与Tomcat比较联系 apache支持静态页,tomcat支持动态的,比如servlet等. 一般使用apache+tomcat的话,apache ...
- Hibernate逍遥游记-第8章 映射组成关系(<component>、<parent>)
一. 1. <?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate ...
- Android Handler之Message传递参数
最近发现Message,发送消息可以传递参数,这个思路很好,所以写了一个例子,点击屏幕,给Activity发送一个消息,传递两个参数,并把这个activity销毁掉! 程序打开界面: 点击屏幕,销毁a ...
- nodejs搭配phantomjs highcharts后台生成图表
简单分享一下,后台使用nodejs结合highcharts.phantomjs生成报表图片的方法.这主要应用在日报邮件. 主要参考以下资料: http://www.highcharts.com/com ...
- 一些非常有用的html,css,javascript代码片段(持久更新)
1.判断设备是否联网 if (navigator.onLine) { //some code }else{ //others code } 2.获取url的指定参数 function getStrin ...
- MyBatis学习总结4--解决字段名与实体类属性名不相同的冲突
在平时的开发中,我们表中的字段名和表对应实体类的属性名称不一定是完全相同的,如果直接在xml映射文件中使用sql进行映射,会造成返回值为空的情况,下面阐述解决方案: 测试所用表和数据 create t ...
- Android中使用Parcelable
今天 在两个Activity之间传集合类型数据,看了一下,要用Parcelable 所以就看一下东西: 下面一段话是复制网友的. Android序列化对象主要有两种方法,实现Serializable接 ...
- sendmessage()模拟鼠标点击
{鼠标软模拟:好处就是不会真的移动鼠标 开始按钮 坐标 x=386y=387 }sendmessage(hookHwnd,messages.WM_LBUTTONDOWN ,0,$0180017A); ...