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

首頁(yè) > 編程 > Python > 正文

Python中用Ctrl+C終止多線程程序的問題解決

2019-11-25 18:39:25
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

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

#!/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()

上面是一個(gè)模擬程序,并不真正向服務(wù)發(fā)送請(qǐng)求,而代之以在一千萬(wàn)以內(nèi),每個(gè)線程每隔并發(fā)數(shù)個(gè)(cc個(gè))打印一個(gè)整數(shù)。很明顯,當(dāng)所有線程都完成自己的任務(wù)后,進(jìn)程會(huì)正常退出。但如果我們中途想退出(試想一個(gè)壓力測(cè)試程序,在中途已經(jīng)發(fā)現(xiàn)了問題,需要停止測(cè)試),該腫么辦?你當(dāng)然可以用ps查找到進(jìn)程號(hào),然后kill -9殺掉,但這樣太繁瑣了,捕捉Ctrl+C是最自然的想法。上面示例程序中已經(jīng)捕捉了這個(gè)信號(hào),并修改全局變量is_exit,線程中會(huì)檢測(cè)這個(gè)變量,及時(shí)退出。

但事實(shí)上這個(gè)程序并不work,當(dāng)你按下Ctrl+C時(shí),程序照常運(yùn)行,并無(wú)任何響應(yīng)。網(wǎng)上搜了一些資料,明白是python的子線程如果不是daemon的話,主線程是不能響應(yīng)任何中斷的。但設(shè)為daemon后主線程會(huì)隨之退出,接著整個(gè)進(jìn)程很快就退出了,所以還需要在主線程中檢測(cè)各個(gè)子線程的狀態(tài),直到所有子線程退出后自己才退出,因此上例29行之后的代碼可以修改為:

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

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

重新試一下,問題依然沒有解決,進(jìn)程還是沒有響應(yīng)Ctrl+C,這是因?yàn)閖oin()函數(shù)同樣會(huì)waiting在一個(gè)鎖上,使主線程無(wú)法捕獲信號(hào)。因此繼續(xù)修改,調(diào)用線程的isAlive()函數(shù)判斷線程是否完成:

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

while 1:
         alive = False
         for i in range(cc):
             alive = alive or threads[i].isAlive()
         if not alive:
             break

這樣修改后,程序完全按照預(yù)想運(yùn)行了:可以順利的打印每個(gè)線程應(yīng)該打印的所有數(shù)字,也可以中途用Ctrl+C終結(jié)整個(gè)進(jìn)程。完整的代碼如下:

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

#!/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

其實(shí),如果用python寫一個(gè)服務(wù),也需要這樣,因?yàn)樨?fù)責(zé)服務(wù)的那個(gè)線程是永遠(yuǎn)在那里接收請(qǐng)求的,不會(huì)退出,而如果你想用Ctrl+C殺死整個(gè)服務(wù),跟上面的壓力測(cè)試程序是一個(gè)道理。總結(jié)一下,python多線程中要響應(yīng)Ctrl+C的信號(hào)以殺死整個(gè)進(jìn)程,需要:

1.把所有子線程設(shè)為Daemon;
2.使用isAlive()函數(shù)判斷所有子線程是否完成,而不是在主線程中用join()函數(shù)等待完成;
3.寫一個(gè)響應(yīng)Ctrl+C信號(hào)的函數(shù),修改全局變量,使得各子線程能夠檢測(cè)到,并正常退出。

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 鄱阳县| 安徽省| 柯坪县| 和平县| 玉门市| 大邑县| 江川县| 平昌县| 微博| 兴仁县| 双峰县| 萨嘎县| 固始县| 屯昌县| 余庆县| 盘锦市| 怀宁县| 双峰县| 鸡东县| 登封市| 扎囊县| 宜黄县| 太原市| 宁强县| 长沙县| 靖江市| 明星| 如皋市| 安吉县| 玛纳斯县| 龙胜| 兴化市| 开鲁县| 思南县| 崇义县| 屏东市| 高雄县| 郸城县| 泽普县| 灵宝市| 澄城县|