Pythonを介して外部プログラムを実行しています。subprocess.Popen()
を使用して、または を使用して、外部プログラムを呼び出すための最良の選択を知りたいですsubprocess.call()
。また、経過時間、外部プログラムが使用するメモリと CPU の量を測定する必要があります。については聞いたことがpsutil
ありますが、どれを選択すればよいかよくわかりません。
1 に答える
また、extern プログラムで使用される経過時間、メモリ量、および CPU を測定する必要があります。
(私は、あなたがプラットフォームの で入手できる情報だけが必要であると仮定しますrusage
。また、Windows にはそのような機能がまったくないため、Windows については気にしないと仮定します。追加情報が必要な場合は、プラットフォーム固有の方法 (Linux のproc
ファイルシステムから読み取る、または AIX のモニター API を呼び出すなど) で利用できますが、stdlib ではこれを行うことはほとんどできず、psutil
答えは唯一のものです。)
subprocess
ライブラリは の呼び出しを終了しfork
、次に子の -family 関数execv
とwaitpid
親の -family 関数を呼び出します。(これは、ソースから開始して、call
そこから他の呼び出しをたどることで確認できます。)
wait3
残念ながら、子からリソースの使用状況を取得する簡単な方法は、 orwait4
ではなくwait
orを呼び出すことwaitpid
です。それでsubprocess
、あなたはあなたが望むものに狂ったように近づくことができますが、完全にはそこにはなりません.
ただし、いくつかのオプションがあります。
- 子プロセスが 1 つしかない場合
getrusage(RUSAGE_CHILDREN)
は、これで十分です。 - プロセスを起動してから
psutil
(またはプラットフォーム固有のコード) を使用しproc.pid
て、子を取得する前にリソース情報を取得できます。 psutil
置き去りにして、すべてを行うために使用できますsubprocess
。- サブクラス化
subprocess.Popen
してそのメソッドをオーバーライドできますwait
。
最後のものは、思ったよりずっと単純です。os.waitpid
ソースを見ると、実際に が呼び出される場所は 3つしかなく、そのうちの 1 つだけがコードに影響を与えます。にあるものだと思います_try_wait
。だから(テストされていない):
class ResourcePopen(subprocess.Popen):
def _try_wait(self, wait_flags):
"""All callers to this function MUST hold self._waitpid_lock."""
try:
(pid, sts, res) = _eintr_retry_call(os.wait4, self.pid, wait_flags)
except OSError as e:
if e.errno != errno.ECHILD:
raise
# This happens if SIGCLD is set to be ignored or waiting
# for child processes has otherwise been disabled for our
# process. This child is dead, we can't get the status.
pid = self.pid
sts = 0
else:
self.rusage = res
return (pid, sts)
def resource_call(*popenargs, timeout=None, **kwargs):
"""Run command with arguments. Wait for command to complete or
timeout, then return the returncode attribute and resource usage.
The arguments are the same as for the Popen constructor. Example:
retcode, rusage = call(["ls", "-l"])
"""
with ResourcePopen(*popenargs, **kwargs) as p:
try:
retcode = p.wait(timeout=timeout)
return retcode, p.rusage
except:
p.kill()
p.wait()
raise
そしていま:
retcode, rusage = resource_call(['spam', 'eggs'])
print('spam used {}s of system time'.format(rusage.ru_stime))
ハイブリッドを使用する場合と比較してくださいpsutil
(多くのプラットフォームでこの方法を使用しても機能しません…):
p = subprocess.Popen(['spam', 'eggs'])
ps = psutil.Process(p.pid)
p.wait()
print('spam used {}s of system time'.format(ps.cpu_times().system))
もちろん、後者は正当な理由でより複雑ではありません。より強力で柔軟性があるため、より複雑です。また、含まれていないすべての種類のデータを取得することもできます。またrusage
、プロセスが完了するまで待つのではなく、プロセスの実行中に毎秒情報を取得することもできます。また、Windows で使用することもできます…</p>