3

Pythonを介して外部プログラムを実行しています。subprocess.Popen()を使用して、または を使用して、外部プログラムを呼び出すための最良の選択を知りたいですsubprocess.call()。また、経過時間、外部プログラムが使用するメモリと CPU の量を測定する必要があります。については聞いたことがpsutilありますが、どれを選択すればよいかよくわかりません。

4

1 に答える 1

10

また、extern プログラムで使用される経過時間、メモリ量、および CPU を測定する必要があります。

(私は、あなたがプラットフォームの で入手できる情報だけが必要であると仮定しますrusage。また、Windows にはそのような機能がまったくないため、Windows については気にしないと仮定します。追加情報が必要な場合は、プラットフォーム固有の方法 (Linux のprocファイルシステムから読み取る、または AIX のモニター API を呼び出すなど) で利用できますが、stdlib ではこれを行うことはほとんどできず、psutil答えは唯一のものです。)

subprocessライブラリは の呼び出しを終了しfork、次に子の -family 関数execvwaitpid親の -family 関数を呼び出します。(これは、ソースから開始して、callそこから他の呼び出しをたどることで確認できます。)

wait3残念ながら、子からリソースの使用状況を取得する簡単な方法は、 orwait4ではなくwaitorを呼び出すこと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>

于 2014-10-20T22:36:01.957 に答える