2009-10-26 12 views
9

別のスレッドで開始したサブプロセスを殺すとき、通信パイプをシャットダウンすることが可能になるのだろうか。私がcommunicate()を呼び出さなければ、kill()は期待どおりに動作し、5秒ではなく1秒後にプロセスを終了します。pythonサブプロセスPopenで開始されたプロセスを強制終了するときにstdout-pipeを閉じるにはどうしたらいいですか?

私は同様の問題hereの議論を見つけましたが、私は本当の答えを得ませんでした。私は、いずれかのパイプを閉じるためにまたは明示的に(この例では「スリープ」である)サブサブプロセスを殺し、パイプのブロックを解除することを殺すことができなければならないと仮定する。

私はまた、SOに答え、彼女を見つけることを試みたが、私は直接私の知る限り、この問題に対処していないthisthisthisを、見出しました(?)。

だから私はやりたい事は、第二のスレッドでコマンドを実行し、そのすべての出力を得るが、私はそう望む時に即座にそれを殺すことができることができるようにすることです。私はファイルやテールを経由して似たようなことができますが、これを行うにはもっと良い方法があると思いますか?あなたがPythonの超粗粒度の並行処理の犠牲者かもしれように見えます

#!/bin/bash 
echo "sleeping five" 
sleep 5 
echo "slept five" 

出力

$ time python poc.py 
process: sleeping five 

real 0m5.053s 
user 0m0.044s 
sys 0m0.000s 
+0

、 '。/ ascript.sh'は死ぬが、その中に'睡眠は5'ません。興味深いことに、 '。/ ascript.sh'が消滅した直後にPythonが戻ってこないということです。 –

答えて

6

は、私はこの問題は、bashスクリプトのではなく、サブプロセス()のみ直接の子プロセス(bashのを)殺すことprocess.killであると思います。

問題と解決策をここで説明されています

使用popenの(...、preexec_fnに= os.setsid)プロセスグループとOSを作成します。プロセスグループ全体を強制終了するpgkill。例えば、 `process.killで()が`と呼ばれている

import os 
import signal 
import subprocess 
import time 
from threading import Thread 

process = None 

def executeCommand(command, runCommand): 
    Thread(target=runCommand, args=(command,)).start() 

def runCommand(command): 
    global process 
    args = command.strip().split() 
    process = subprocess.Popen(
     args, shell=False, stdout=subprocess.PIPE, preexec_fn=os.setsid) 

    for line in process.communicate(): 
     if line: 
      print "process:", line, 

if __name__ == '__main__': 
    executeCommand("./ascript.sh", runCommand) 
    time.sleep(1) 
    os.killpg(process.pid, signal.SIGKILL) 

$ time python poc.py 
process: sleeping five 

real 0m1.051s 
user 0m0.032s 
sys 0m0.020s 
-1

import subprocess, time 
from threading import Thread 

process = None 

def executeCommand(command, runCommand): 
    Thread(target=runCommand, args=(command,)).start() 

def runCommand(command): 
    global process 
    args = command.strip().split() 
    process = subprocess.Popen(args, shell=False, stdout=subprocess.PIPE) 

    for line in process.communicate(): 
     if line: 
      print "process:", line, 

if __name__ == '__main__': 
    executeCommand("./ascript.sh", runCommand) 
    time.sleep(1) 
    process.kill() 

この

はスクリプトです。

#!/bin/bash 
echo "sleeping five" 
sleep 5 
echo "sleeping five again" 
sleep 5 
echo "slept five" 

をそして出力は次のようになります:これにスクリプトを変更し

process: sleeping five 

real 0m5.134s 
user 0m0.000s 
sys  0m0.010s 

を全体スクリプトが実行した場合、時間は10秒になります。したがって、Pythonコントロールスレッドは、bashスクリプトがスリープするまで実際には実行されません。あなたはこれにスクリプトを変更した場合も同様、:

#!/bin/bash 
echo "sleeping five" 
sleep 1 
sleep 1 
sleep 1 
sleep 1 
sleep 1 
echo "slept five" 

その後、出力は次のようになります。要するに

process: sleeping five 

real 0m1.150s 
user 0m0.010s 
sys  0m0.020s 

、あなたのコードは、論理的に実装され動作します。 :)

+0

この例のスリープは、スクリプトで行われている長い操作のプレースホルダに過ぎません。問題は、コードがcommuncate()でハングしないようにパイプをシャットダウンするにはどうすればいいですか?あるいは、ブロックを解放するためにどの「サブ・サブプロセス」を殺すかをどのようにして知ることができますか? – icecream

+0

グローバルインタープリタロックは仕事では大変ですか? http://docs.python.org/c-api/init.html#thread-state-and-the-global-interpreterlock –

+0

できますか?助言がありますか? – icecream

0

これを実行してマルチスレッドの問題を回避する最も簡単な方法は、メインスレッドからkillフラグを設定し、通信を開始する直前にスクリプト実行スレッドでそのフラグをチェックすることですフラグがTrueの場合のスクリプト

+0

実際には、マルチスレッドの問題よりもパイプのブロッキングに問題があります。私は別のスレッドが必要なので、どこかからシャットダウンすることができます。私がシェルから "kill"すると、スクリプトとそのサブプロセスが強制終了されます。 Pythonのkillは、パイプをシャットダウンする必要があると思われるため、これを実行できません。 – icecream