簡體   English   中英

如何殺死由 popen 創建並使用通信()的進程?

[英]How to kill a process which is create by popen and uses communicate()?

我有一個程序P1 ,我需要使用不同的輸入運行大約 24*20000 次。 問題是P1掛起,我應該手動強制它( kill )。 我的第一個解決方案是編寫一個 python 腳本來調用P1並傳遞正確的輸入並使用popencommunicate接收 output 。 但是由於等待 output 的通信的性質,只要它在等待響應,我就無法終止該進程。 我在 Windows。

我嘗試使用multiprocess進程 function,但它只運行P1並且無法將輸入發送給它。 我懷疑不在popen中使用管道並嘗試了一點,但我想我無法從P1收到 output 。

有任何想法嗎?

# This code run XLE and pass the intended input to it automatically
 def startExe(programPath, programArgStr):
 p = subprocess.Popen(programPath,stdout=subprocess.PIPE,stdin=subprocess.PIPE) p.stdin.write(programArgStr)
 p.communicate()[0]
# Need to kill the process if it takes longer than it should here

def main(folder): 
.. 
#loop
programArgStr = "create-parser"+path1+";cd "+ path2+"/s"+ command(counter) +";exit"

startExe(path, programArgStr)
..

如您所見,P1 是否可以成功完成給定任務,它可以使用傳遞給它的退出命令自行退出!

如果您不需要使用 Python,您可以考慮使用 Cygwin Bash 和timeout(1)命令來運行帶有超時的命令。 但是,由於 Cygwin 的fork()實現不是很快,並且您正在創建大量進程,因此僅創建進程可能會產生巨大的開銷(我不知道 Python 的本機 Windows 版本是否是在這方面更好)。

或者,如果您有P1的源代碼,為什么不直接修改它,以便它可以在一次調用中執行多次迭代呢? 這樣,您不必處理創建和殺死 480,000 個進程,如果每次調用所做的工作量很小,這將產生巨大的差異。

當您調用popen時,您可以指定 pipe 或文件描述符以接受來自進程的標准輸出:

Popen(args, bufsize=0, executable=None, stdin=None, stdout=None , stderr=None, preexec_fn=None, close_fds=False, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=無,創建標志 = 0)

然后,您可以監視傳遞給 popen 的文件/管道,如果沒有寫入,則終止該進程。

有關 popen args 的更多信息在python 文檔中。

與其使用p.communicate ,不如嘗試遍歷 output 的行:

while True:
    line = p.stdout.readline()
    if not line:
        break
    print ">>> " + line.rstrip()

這種方法怎么樣?

from threading import Thread
def main(input):
    #your actual program, modified to take input as argument
queue = ['Your inputs stored here. Even better to make it to be a generator']
class Runner(Thread):
    def __init__(self):
        Thread.__init__(self)
    def run(self):
        while len(queue)>0:
            input = queue.pop()
            main(input)
        return True
#Use 24 threads
for thread in xrange(24):
    Runner().start()
#You may also join threads at the end.

當然這種方法會引入一些漏洞,例如“兩個線程同時彈出隊列列表”,但我在現實生活中從未遇到過。

我通過編輯當前代碼並將殺手代碼放在單獨的文件中解決了我的問題。 為此,我添加了一行來將新創建的進程的 PID 寫入文件中。

    #//Should come before p.commiunicate
    WriteStatus(str(p.pid) + "***" + str(gmtime().tm_hour) + "***" + str(gmtime().tm_min))        
    p.communicate()[0]

並且進程監視器單獨執行並每 2 分鍾檢查一次,以查看文件中列出的進程是否仍然處於活動狀態。 如果是,則殺死他們並刪除他們的 ID。

 def KillProcess(pid):

    subprocess.Popen("TASKKILL /PID "+ str(pid) + " /F /T" , shell=True)
    subprocess.Popen("TASKKILL /im WerFault.exe /F /T" , shell=True)
    print "kill"

    def ReadStatus(filePath):
    print "Checking" + filePath
    try:
            status = open(mainPath+filePath, 'r').readline()
    except:
            print "file removed" + filePath
            return 0
    if len(status) >0:
            info = status.split("***")                
            time = [gmtime().tm_hour, gmtime().tm_min]
            print time

            # Time deifferences
            difHour = time[0]- int(info[1])
            if difHour == 0: # in the same hour
                    difMin =  time[1]- int(info[2])
            else:
                    difMin = 60 - int(info[2]) + time[1]
            if difMin > 2:
                    try:
                            open(mainPath+filePath, 'w').write("")
                            KillProcess(info[0])
                    except:
                            pass
    return 1

  def monitor():
    # Read all the files
    listFiles = os.listdir(mainPath)
    while len(listFiles)>0:
            #GO and check the contents
            for file in listFiles:
                    #Open the file and Calculate if the process should be killed or not
                    pid = ReadStatus(file)
                    #Update listFiles due to remove of file after finishing the process '
                    # of each folder is done
                    listFiles = os.listdir(mainPath)
            for i in range(0,4):
                    time.sleep(30) #waits 30 sec
                    subprocess.Popen("TASKKILL /im WerFault.exe /F /T" , shell=True)
    #to indicate the job is done
    return 1

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM