场景:

经常会遇到下述问题:很多io busy的应用采取多线程的方式来解决,但这时候会发现python命令行不响应ctrl-c 了,而对应的java代码则没有问题:

  1. public class Test {
  2. public static void main(String[] args) throws Exception {
  3. new Thread(new Runnable() {
  4. public void run() {
  5. long start = System.currentTimeMillis();
  6. while (true) {
  7. try {
  8. Thread.sleep(1000);
  9. } catch (Exception e) {
  10. }
  11. System.out.println(System.currentTimeMillis());
  12. if (System.currentTimeMillis() - start > 1000 * 100) break;
  13. }
  14. }
  15. }).start();
  16. }
  17. }

java Test

ctrl-c则会结束程序

而对应的python代码:

  1. # -*- coding: utf-8 -*-
  2. import time
  3. import threading
  4. start=time.time()
  5. def foreverLoop():
  6. start=time.time()
  7. while 1:
  8. time.sleep(1)
  9. print time.time()
  10. if time.time()-start>100:
  11. break
  12. thread_=threading.Thread(target=foreverLoop)
  13. #thread_.setDaemon(True)
  14. thread_.start()

python p.py

后ctrl-c则完全不起作用了。

不成熟的分析:

首先单单设置 daemon 为 true 肯定不行,就不解释了。当daemon为 false 时,导入python线程库后实际上,threading会在主线程执行完毕后,检查是否有不是 daemon 的线程,有的化就wait,等待线程结束了,在主线程等待期间,所有发送到主线程的信号也会被阻测,可以在上述代码加入signal模块验证一下:

  1. def sigint_handler(signum,frame):
  2. print "main-thread exit"
  3. sys.exit()
  4. signal.signal(signal.SIGINT,sigint_handler)

在100秒内按下ctrl-c没有反应,只有当子线程结束后才会出现打印 "main-thread exit",可见 ctrl-c被阻测了

threading 中在主线程结束时进行的操作:

  1. _shutdown = _MainThread()._exitfunc
  2. def _exitfunc(self):
  3. self._Thread__stop()
  4. t = _pickSomeNonDaemonThread()
  5. if t:
  6. if __debug__:
  7. self._note("%s: waiting for other threads", self)
  8. while t:
  9. t.join()
  10. t = _pickSomeNonDaemonThread()
  11. if __debug__:
  12. self._note("%s: exiting", self)
  13. self._Thread__delete()

对所有的非daemon线程进行join等待,其中join中可自行察看源码,又调用了wait,同上文分析 ,主线程等待到了一把锁上。

不成熟的解决:

只能把线程设成daemon才能让主线程不等待,能够接受ctrl-c信号,但是又不能让子线程立即结束,那么只能采用传统的轮询方法了,采用sleep间歇省点cpu吧:

  1. # -*- coding: utf-8 -*-
  2. import time,signal,traceback
  3. import sys
  4. import threading
  5. start=time.time()
  6. def foreverLoop():
  7. start=time.time()
  8. while 1:
  9. time.sleep(1)
  10. print time.time()
  11. if time.time()-start>5:
  12. break
  13. thread_=threading.Thread(target=foreverLoop)
  14. thread_.setDaemon(True)
  15. thread_.start()
  16. #主线程wait住了,不能接受信号了
  17. #thread_.join()
  18. def _exitCheckfunc():
  19. print "ok"
  20. try:
  21. while 1:
  22. alive=False
  23. if thread_.isAlive():
  24. alive=True
  25. if not alive:
  26. break
  27. time.sleep(1)
  28. #为了使得统计时间能够运行,要捕捉  KeyboardInterrupt :ctrl-c
  29. except KeyboardInterrupt, e:
  30. traceback.print_exc()
  31. print "consume time :",time.time()-start
  32. threading._shutdown=_exitCheckfunc

缺点:轮询总会浪费点cpu资源,以及battery.

有更好的解决方案敬请提出。

ps1: 进程监控解决方案 :

用另外一个进程来接受信号后杀掉执行任务进程,牛

  1. # -*- coding: utf-8 -*-
  2. import time,signal,traceback,os
  3. import sys
  4. import threading
  5. start=time.time()
  6. def foreverLoop():
  7. start=time.time()
  8. while 1:
  9. time.sleep(1)
  10. print time.time()
  11. if time.time()-start>5:
  12. break
  13. class Watcher:
  14. """this class solves two problems with multithreaded
  15. programs in Python, (1) a signal might be delivered
  16. to any thread (which is just a malfeature) and (2) if
  17. the thread that gets the signal is waiting, the signal
  18. is ignored (which is a bug).
  19. The watcher is a concurrent process (not thread) that
  20. waits for a signal and the process that contains the
  21. threads.  See Appendix A of The Little Book of Semaphores.
  22. http://greenteapress.com/semaphores/
  23. I have only tested this on Linux.  I would expect it to
  24. work on the Macintosh and not work on Windows.
  25. """
  26. def __init__(self):
  27. """ Creates a child thread, which returns.  The parent
  28. thread waits for a KeyboardInterrupt and then kills
  29. the child thread.
  30. """
  31. self.child = os.fork()
  32. if self.child == 0:
  33. return
  34. else:
  35. self.watch()
  36. def watch(self):
  37. try:
  38. os.wait()
  39. except KeyboardInterrupt:
  40. # I put the capital B in KeyBoardInterrupt so I can
  41. # tell when the Watcher gets the SIGINT
  42. print 'KeyBoardInterrupt'
  43. self.kill()
  44. sys.exit()
  45. def kill(self):
  46. try:
  47. os.kill(self.child, signal.SIGKILL)
  48. except OSError: pass
  49. Watcher()
  50. thread_=threading.Thread(target=foreverLoop)
  51. thread_.start()

 注意 watch()一定要放在线程创建前,原因未知。。。。,否则立刻就结束

python多线程ctrl-c退出问题的更多相关文章

  1. python多线程threading

    本文通过 4个example 介绍python中多线程package —— threading的常用用法, 包括调用多线程, 同步队列类Queue, Ctrl+c结束多线程. example1. 调用 ...

  2. [转]python 多线程threading简单分析

    多线程和多进程是什么自行google补脑 对于python 多线程的理解,我花了很长时间,搜索的大部份文章都不够通俗易懂.所以,这里力图用简单的例子,让你对多线程有个初步的认识. 单线程 在好些年前的 ...

  3. python多线程学习记录

    1.多线程的创建 import threading t = t.theading.Thread(target, args--) t.SetDeamon(True)//设置为守护进程 t.start() ...

  4. python多线程编程

    Python多线程编程中常用方法: 1.join()方法:如果一个线程或者在函数执行的过程中调用另一个线程,并且希望待其完成操作后才能执行,那么在调用线程的时就可以使用被调线程的join方法join( ...

  5. Python 多线程教程:并发与并行

    转载于: https://my.oschina.net/leejun2005/blog/398826 在批评Python的讨论中,常常说起Python多线程是多么的难用.还有人对 global int ...

  6. python 多线程就这么简单(转)

    多线程和多进程是什么自行google补脑 对于python 多线程的理解,我花了很长时间,搜索的大部份文章都不够通俗易懂.所以,这里力图用简单的例子,让你对多线程有个初步的认识. 单线程 在好些年前的 ...

  7. 【python,threading】python多线程

    使用多线程的方式 1.  函数式:使用threading模块threading.Thread(e.g target name parameters) import time,threading def ...

  8. Python多线程和Python的锁

    Python多线程 Python中实现多线程有两种方式,一种基于_thread模块(在Python2.x版本中为thread模块,没有下划线)的start_new_thread()函数,另一种基于th ...

  9. 【跟我一起学Python吧】Python 多线程

    其实自我感觉Python的多线程很类似于Java的多线程机制,但是比JAVA的多线程更灵活.在早期的Python多线程实现中,采用了thread模块.例如: from time import ctim ...

  10. 关于python多线程编程中join()和setDaemon()的一点儿探究

    关于python多线程编程中join()和setDaemon()的用法,这两天我看网上的资料看得头晕脑涨也没看懂,干脆就做一个实验来看看吧. 首先是编写实验的基础代码,创建一个名为MyThread的  ...

随机推荐

  1. lintcode:strStr 字符串查找

    题目: 字符串查找 字符串查找(又称查找子字符串),是字符串操作中一个很有用的函数.你的任务是实现这个函数. 对于一个给定的 source 字符串和一个 target 字符串,你应该在 source ...

  2. 实用Photoshop快捷键

    面板快捷键:shift+对应的快捷键调用同类工具 Ctrl + 点击面板------获取选取 Shift + F6-----------羽化 Alt + Delete---------填充前景色 Ct ...

  3. POJ2891——Strange Way to Express Integers(模线性方程组)

    Strange Way to Express Integers DescriptionElina is reading a book written by Rujia Liu, which intro ...

  4. 如何查看linux是32位还是64位

    可以用命令“getconf LONG_BIT”查看,如果返回的结果是32则说明是32位,返回的结果是64则说明是64位. 此外还可以使用命令“uname -a”查看,输出的结果中,如果有x86_64就 ...

  5. 机器人学 —— 飞行机器人(Introduction)

    UPNN课程 aerial robotics 教授: VJ  Kummer 1.四旋翼飞行器的控制对象是各个旋翼对应的电机 2.飞行器的能源主要消耗于hovering. 3.飞行器在设计时需要考虑各个 ...

  6. Android Include标签

    编程的世界有的时候很微妙,有的时候就好像是在解决一个哲学问题,Android开发的时候,所有的布局,颜色,等(其实这些都可以称之为资源,Android中的资源是指非代码部分,如图片.音频.视频.字符等 ...

  7. JDBC学习总结(一)

    1.JDBC概述     JDBC是一种可以执行SQL语句并可返回结果的Java API,其全称是Java DataBase Connectivity,也是一套面向对象的应用程序接口API,它由一组用 ...

  8. 【转载】R6034错误,C Runtime Error

    能查到的解决方法都在里面有提及: 我是使用 stdafx.h加入这句 code #pragma comment(linker, "\"/manifestdependency:typ ...

  9. HDU 4675 GCD of Sequence(容斥)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4675 题意:给出n,m,K,一个长度为n的数列A(1<=A[i]<=m).对于d(1< ...

  10. Interpolated Strings

    https://msdn.microsoft.com/en-us/library/dn961160.aspx ; // Before C# 6.0 System.Console.WriteLine(S ...