日韩久久久精品,亚洲精品久久久久久久久久久,亚洲欧美一区二区三区国产精品 ,一区二区福利

探尋python多線程ctrl+c退出問題解決方案

系統(tǒng) 1903 0

場(chǎng)景:

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

復(fù)制代碼 代碼如下:

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則會(huì)結(jié)束程序

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

復(fù)制代碼 代碼如下:

# -*- 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則完全不起作用了。

不成熟的分析:

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

復(fù)制代碼 代碼如下:

def sigint_handler(signum,frame):???
??? print "main-thread exit"?
??? sys.exit()???
signal.signal(signal.SIGINT,sigint_handler)?

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

threading 中在主線程結(jié)束時(shí)進(jìn)行的操作:

復(fù)制代碼 代碼如下:

_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()?
?

?對(duì)所有的非daemon線程進(jìn)行join等待,其中join中可自行察看源碼,又調(diào)用了wait,同上文分析 ,主線程等待到了一把鎖上。

不成熟的解決:

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

復(fù)制代碼 代碼如下:

# -*- 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住了,不能接受信號(hào)了?
#thread_.join()?
?
def _exitCheckfunc():?
??? print "ok"?
??? try:?
??????? while 1:?
??????????? alive=False?
??????????? if thread_.isAlive():?
??????????????? alive=True?
??????????? if not alive:?
??????????????? break?
??????????? time.sleep(1)???
??? #為了使得統(tǒng)計(jì)時(shí)間能夠運(yùn)行,要捕捉? KeyboardInterrupt :ctrl-c???????
??? except KeyboardInterrupt, e:?
??????? traceback.print_exc()?
??? print "consume time :",time.time()-start?
?????????
threading._shutdown=_exitCheckfunc?

?? 缺點(diǎn):輪詢總會(huì)浪費(fèi)點(diǎn)cpu資源,以及battery.

有更好的解決方案敬請(qǐng)?zhí)岢觥?

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

用另外一個(gè)進(jìn)程來接受信號(hào)后殺掉執(zhí)行任務(wù)進(jìn)程,牛

復(fù)制代碼 代碼如下:

# -*- 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()一定要放在線程創(chuàng)建前,原因未知。。。。,否則立刻就結(jié)束


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長(zhǎng)會(huì)非常 感謝您的哦?。?!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 朝阳区| 西安市| 桃江县| 富平县| 澎湖县| 竹北市| 建平县| 巨鹿县| 玉林市| 万宁市| 杭锦后旗| 洛扎县| 肃北| 凤山市| 沈丘县| 姜堰市| 黄平县| 尉犁县| 天镇县| 射洪县| 阿鲁科尔沁旗| 东至县| 奉贤区| 东城区| 连山| 平陆县| 无极县| 临汾市| 友谊县| 武汉市| 乌拉特中旗| 岚皋县| 嵩明县| 佛坪县| 年辖:市辖区| 银川市| 青州市| 陈巴尔虎旗| 比如县| 永新县| 右玉县|