国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計 > 正文

python多線程ctrl-c退出問題

2019-11-14 17:32:54
字體:
供稿:網(wǎng)友

場景:

 

經(jīng)常會遇到下述問題:很多io busy的應(yīng)用采取多線程的方式來解決,但這時候會發(fā)現(xiàn)python命令行不響應(yīng)ctrl-c 了,而對應(yīng)的java代碼則沒有問題:

 

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

java Test

ctrl-c則會結(jié)束程序

 

而對應(yīng)的python代碼:

 

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.               
  13.   
  14. thread_=threading.Thread(target=foreverLoop)  
  15. #thread_.setDaemon(True)  
  16. thread_.start()  

 

python p.py

 

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

 

 

不成熟的分析:

 

首先單單設(shè)置 daemon 為 true 肯定不行,就不解釋了。當(dāng)daemon為 false 時,導(dǎo)入python線程庫后實際上,threading會在主線程執(zhí)行完畢后,檢查是否有不是 daemon 的線程,有的化就wait,等待線程結(jié)束了,在主線程等待期間,所有發(fā)送到主線程的信號也會被阻測,可以在上述代碼加入signal模塊驗證一下:

 

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

 

在100秒內(nèi)按下ctrl-c沒有反應(yīng),只有當(dāng)子線程結(jié)束后才會出現(xiàn)打印 "main-thread exit",可見 ctrl-c被阻測了

 

threading 中在主線程結(jié)束時進行的操作:

Python代碼  收藏代碼
  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中可自行察看源碼,又調(diào)用了wait,同上文分析 ,主線程等待到了一把鎖上。

 

不成熟的解決:

 

只能把線程設(shè)成daemon才能讓主線程不等待,能夠接受ctrl-c信號,但是又不能讓子線程立即結(jié)束,那么只能采用傳統(tǒng)的輪詢方法了,采用sleep間歇省點cpu吧:

 

Python代碼  收藏代碼
  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.               
  14. thread_=threading.Thread(target=foreverLoop)  
  15. thread_.setDaemon(True)  
  16. thread_.start()  
  17.   
  18. #主線程wait住了,不能接受信號了  
  19. #thread_.join()  
  20.   
  21. def _exitCheckfunc():  
  22.     print "ok"  
  23.     try:  
  24.         while 1:  
  25.             alive=False  
  26.             if thread_.isAlive():  
  27.                 alive=True  
  28.             if not alive:  
  29.                 break  
  30.             time.sleep(1)    
  31.     #為了使得統(tǒng)計時間能夠運行,要捕捉  KeyboardInterrupt :ctrl-c        
  32.     except KeyboardInterrupt, e:  
  33.         traceback.print_exc()  
  34.     print "consume time :",time.time()-start  
  35.           
  36. threading._shutdown=_exitCheckfunc  

   缺點:輪詢總會浪費點cpu資源,以及battery.

 

有更好的解決方案敬請?zhí)岢觥?/strong>

 

ps1: 進程監(jiān)控解決方案 :

 

用另外一個進程來接受信號后殺掉執(zhí)行任務(wù)進程,牛

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

 注意 watch()一定要放在線程創(chuàng)建前,原因未知。。。。,否則立刻就結(jié)束


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 年辖:市辖区| 依兰县| 宝兴县| 林周县| 寿宁县| 蓬溪县| 简阳市| 大余县| 麻江县| 乌恰县| 合肥市| 筠连县| 胶州市| 祁东县| 寿光市| 东台市| 五大连池市| 阳春市| 淮南市| 慈利县| 侯马市| 永善县| 江华| 义乌市| 安丘市| 钟祥市| 罗城| 浑源县| 信丰县| 司法| 通道| 仙桃市| 九龙坡区| 昭苏县| 中宁县| 保德县| 闵行区| 淳安县| 江山市| 河北区| 衡阳市|