質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

1回答

2266閲覧

マルチスレッドで発生したプロセスを kill したい

退会済みユーザー

退会済みユーザー

総合スコア0

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

1クリップ

投稿2020/07/13 17:19

編集2020/07/13 17:43

前提・実現したいこと

以前、マルチスレッドの mainloop() の抜け方について質問した者です。

プログラム自体は思い通りに動いているのですが、最近になってプログラムを実行するとプロセスがどんどん蓄積していくことに気づきました。
蓄積してもプログラム自体は動くのでそれでもいいような気もするのですが、やはり本来は新たに生じたプロセスをその都度 kill した方がいいように思っています。

発生している問題・エラーメッセージ

エラーが発生しているわけではないのですが、プロセスがどんどん蓄積することが問題なのではないかと感じています。

該当のソースコード

python3

1import shutil 2import subprocess 3import sys 4import paramiko 5import scp 6import os 7import cgi 8import concurrent.futures 9from tkinter import * 10from tkinter import ttk 11 12root = Tk() 13 14def delDir(): 15 dir = '/mnt/HDD/localPyserver/dcmTemp' 16 for root, dirs, files in os.walk(dir, topdown=False): 17 for name in files: 18 os.remove(os.path.join(root, name)) 19 for name in dirs: 20 os.rmdir(os.path.join(root, name)) 21 22def scp_get( remoteDir ): 23 with paramiko.SSHClient() as ssh: 24 ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) 25 ssh.connect(hostname='10.242.134.115', port=22, username='user', password='pass') 26 with scp.SCPClient(ssh.get_transport()) as scpc: 27 try: 28 remotePath = remoteDir 29 print(remotePath) 30 scpc.get( remote_path = remoteDir, local_path = '/mnt/HDD/localPyserver/dcmTemp/', recursive = True) 31 except: 32 print('そのディレクトリは存在しません。') 33 34def weasis() : 35 try: 36 subprocess.run('javaws /mnt/HDD/localPyserver/weasis/weasisStart.jnlp', shell=True, check=True) 37 except subprocess.CalledProcessError: 38 print('外部プログラムの実行に失敗しました', file=sys.stderr) 39 40def func2(): 41 pbIndeterminateVer = ttk.Progressbar(orient=HORIZONTAL, length=200, mode='indeterminate') 42 pbIndeterminateVer.pack(side="left") 43 pbIndeterminateVer.start(10) 44 root.geometry("200x40") 45 root.title("download") 46 root.mainloop() 47 48if __name__ == '__main__': 49 50 executor = concurrent.futures.ThreadPoolExecutor(max_workers=2) 51 form = cgi.FieldStorage() 52 path = form.getvalue('path','') 53 delDir() 54 executor.submit( scp_get, path ) 55 func2() 56 weasis()

試したこと

いろいろ実験してみて、func2()を実行すると新たなプロセスが以下のように蓄積していきます。

ps -fA | grep python

root 977 1 0 21:02 ? 00:00:00 /usr/bin/python3 /usr/bin/networkd-dispatcher --run-startup-triggers
user 1645 1631 0 21:02 ? 00:00:00 /home/user/anaconda3/bin/python cgiserver.py
user 1905 1872 0 21:02 ? 00:00:00 python3 /usr/lib/blueberry/safechild /usr/sbin/rfkill event
user 2049 1645 1 21:02 ? 00:00:01 /home/user/anaconda3/bin/python3.7 /mnt/HDD/localPyserver/cgi-bin/openweasis.py
user 2217 1645 0 21:03 ? 00:00:00 /home/user/anaconda3/bin/python3.7 /mnt/HDD/localPyserver/cgi-bin/openweasis.py
user 2362 1645 10 21:04 ? 00:00:02 /home/user/anaconda3/bin/python3.7 /mnt/HDD/localPyserver/cgi-bin/openweasis.py
user 2481 2459 0 21:04 pts/0 00:00:00 grep --color=auto python

そこで、root.destroy() や root.kill() や root.quit() を最後に追加してみても効果はありませんでした。

また、「http://weekendproject9.hatenablog.com/entry/2019/03/01/124444」に書いてあるようなことをやってみると、
意図しないプロセスまで kill されてしまいます。

func2() で発生したプロセスだけを kill することはできるでしょうか?

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

otn

2020/07/14 00:31

タイトルがおかしい。スレッドとプロセスは違います。マルチプロセスですね。
guest

回答1

0

ベストアンサー

Windows10環境でテストしてみましたがroot.mainloop()から先に進みません(weasis()まで到達していない)
Linuxだと到達しているのかもしれませんが、想定通り動作していますか?

それはともかく、プロセスが残っているのは以下の2つが原因だと推測されます。

mainloop()を止める手段を講じていない

時間のかかる処理(scp_get)が終了した時点でroot.destroy()すればプログレスバーのウィンドウは破棄されます。

python

1def scp_get(remoteDir): 2 () 3 try: 4 () 5 except: 6 () 7 finally: # 処理が成功でも失敗でも確実にdestroyできるようfinallyに追加 8 root.destroy()

追記

cgi経由だとroot.destroy()ではプロセスが終了しないことを確認しました。root.quit()ならプロセスが終了します。(windowsでの確認ですが)

subprocessで渡しているプログラムが終了するまでこのプログラムも終了しない。

subprocess.runは相手方のプログラムの終了を待ち合わせます。今回の場合特に相手の終了を待つ必要はないと思われますので相手のプログラムを起動したらpython側はすぐ終了できるようPopenで起動しましょう。Popenでは特別な設定を講じなければ相手プログラムの終了の待ち合わせを行いません。

diff

1- subprocess.run('javaws /mnt/HDD/localPyserver/weasis/weasisStart.jnlp', shell=True, check=True) 2+ subprocess.Popen('javaws /mnt/HDD/localPyserver/weasis/weasisStart.jnlp', shell=True)

投稿2020/07/13 23:06

編集2020/07/14 05:39
hope_mucci

総合スコア4447

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2020/07/14 03:39

hope_mucciさん、ありがとうございます。 環境に関して全く書いておりませんでした。 ubuntu server 18.04 上に tornado があって、データベースで抽出した path をローカルの Linux mint が受け取って、その path を元に dicom ファイルを NAS から scp ダウンロードして、その後 weasis を起動して dicom ファイルを閲覧しています。 そのためには、ubuntu server の tornado もサーバー起動し、またローカルの linux mint でも cgiserver を起動しておく必要がありますが、一応イメージ通りに閲覧できています。 今、自宅ではないので、プログラムを少し変更してLinux mint 同士で実験してみました。 その結果はやはり dicom ファイルは閲覧できていますが、挙動が少しだけ異なります。 subprocess.run('javaws /mnt/HDD/localPyserver/weasis/weasisStart.jnlp', shell=True, check=True)で起動したjavaウインドウを閉じても、プログラムが完全には停止しません。 subprocess.Popen('javaws /home/mituo/localPyserver/weasis/weasisStart.jnlp', shell=True) finally: root.destroy() に変更しても結果は同じです。 そして、新たなプロセスが蓄積していきます。 ところが以下のようにすると、新しいプロセスの蓄積はなくなります。 if __name__ == '__main__': path = '/home/fuji/DCM' delDir() scp_get( path ) weasis() 自宅での実験でも、func2()を呼び出さないようにすればプロセスの蓄積はありませんでした。 なので func2() の私のコードに問題があるような気がしているのですが、どうでしょうか?
hope_mucci

2020/07/14 05:44

検索したらwebサイトを発見したのでそちらも参考にしています。 cgiサーバ経由で試してみたところ、確かにコメント通りの挙動になりました。 追記した通り、destroyの代わりにquitを使うとプロセスが終了するようになりました。試してみてください。 あと、root.quit()はscp_get関数の中で行ってください。分岐した側のスレッドで実行しないとrootを殺せません。
退会済みユーザー

退会済みユーザー

2020/07/15 03:31

hope_mucciさん御回答ありがとうございます。 linux mint 間ではありますが、おっしゃるようにしたら新しいプロセスが蓄積されなくなりました。 あなたのおかげで、いとも簡単に問題が解決しました。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問