pythonマルチスレッドctrl-c終了問題
シーン:
多くのio busyのアプリケーションはマルチスレッドで解決されていますが、pythonコマンドラインはctrl-cに応答しませんが見つかり、対応するjavaコードは問題ありません.
java Test
ctrl-cはプログラムを終了します
対応するpythonコード:
python p.py
後ctrl-cは全く機能しなくなった.
未熟な分析:
まずdaemonをtrueに設定するだけではだめだと説明しません.daemonがfalseの場合、pythonスレッドライブラリをインポートすると、実際にはthreadingはメインスレッドの実行が完了した後、daemonではないスレッドがあるかどうかをチェックし、ある化はwaitで、待機スレッドが終了し、メインスレッドの待機中にメインスレッドに送信されたすべての信号も阻止され、上記のコードにsignalモジュールを加えて検証することができます.
100秒以内にctrl-cを押すと反応せず、サブスレッドが終了した後にのみ「main-thread exit」が印刷され、ctrl-cが阻害されていることがわかる
threadingでメインスレッドの終了時に行われる操作:
すべての非daemonスレッドに対してjoin待機を行い、joinではソースコードを自分で見ることができ、wait、ぜんぶんせきを呼び出し、メインスレッドはロックに待機した.
未熟な解決:
スレッドをdaemonに設定してこそ、プライマリスレッドを待たずにctrl-c信号を受け入れることができるが、サブスレッドをすぐに終了させることはできない.従来のポーリング方法を採用するしかない.sleep間欠省点cpuを採用しよう.
欠点:ポーリングはcpuリソースとbatteryを浪費します.
より良い解決策がありますので、ご提案ください.
ps1: プロセス監視ソリューション :
別のプロセスで信号を受信した後、タスクを実行するプロセスを殺します.
注意watch()はスレッドが作成される前に必ず置く必要があります.理由は不明です...さもないとすぐ終わる
ps2: 同様のポーリングjoin timeout
私の実现とあまりにも似ていて、残念ながら后で総括する时やっと発见して、脳の细胞を浪费します
多くの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()はスレッドが作成される前に必ず置く必要があります.理由は不明です...さもないとすぐ終わる
ps2: 同様のポーリングjoin timeout
私の実现とあまりにも似ていて、残念ながら后で総括する时やっと発见して、脳の细胞を浪费します