8

「速い」は少し主観的であることを認識しているので、いくつかのコンテキストで説明します。私は、クロスプラットフォームの方法でプロセス情報を読み取るためのpsutilという Python モジュールに取り組んでいます。関数の 1 つはpid_exists(pid)、PID が現在のプロセス リストにあるかどうかを判断するための関数です。

現在、私はEnumProcesses()を使用してプロセス リストを取得し、リストを操作して PID を探しているという明白な方法でこれを行っています。kill(pid, 0)ただし、いくつかの単純なベンチマークでは、PID が存在するかどうかを判断するために 0 シグナルを使用している UNIX ベースのプラットフォーム (Linux、OS X、FreeBSD) の pid_exists 関数よりも大幅に遅いことが示されています。追加のテストでは、ほとんどの時間を占めているのは EnumProcesses であることが示されています。

EnumProcesses を使用して PID が存在するかどうかを判断するよりも速い方法を知っている人はいますか? OpenProcess()を試して、存在しないプロセスを開くエラーをチェックしましたが、これは EnumProcesses リストを反復するよりも 4 倍以上遅いことが判明したので、それも同様です。他の(より良い)提案はありますか?

: これは、pywin32 拡張機能などのサードパーティの lib 依存関係を回避することを目的とした Python ライブラリです。現在のコードよりも高速で、標準の Python ディストリビューションにない pywin32 やその他のモジュールに依存しないソリューションが必要です。

編集: 明確にするために、プロセス情報の読み取りに固有の競合状態があることをよく認識しています。データ収集中にプロセスが停止した場合、または他の問題が発生した場合は、例外を発生させます。pid_exists() 関数は、適切なエラー処理を置き換えることを意図していません。

更新: どうやら私の以前のベンチマークには欠陥があったようです - C でいくつかの簡単なテスト アプリを書きまし

4

4 に答える 4

8

OpenProcessは、すべてを列挙する必要がないことを示している可能性があります。どのくらい速いかわかりません。

編集GetExitCodeProcess:からハンドルを取得した場合でも、プロセスの状態を確認する必要があることに注意してくださいOpenProcess

于 2009-02-26T22:41:23.947 に答える
4

後のテストで、OpenProcessとGetExitCodeProcessは、結局EnumProcessesを使用するよりもはるかに高速であることが明らかになったため、私のベンチマークには明らかに欠陥があることがわかりました。何が起こったのかわかりませんが、いくつかの新しいテストを行い、これがより高速なソリューションであることを確認しました。

int pid_is_running(DWORD pid)
{
    HANDLE hProcess;
    DWORD exitCode;

    //Special case for PID 0 System Idle Process
    if (pid == 0) {
        return 1;
    }

    //skip testing bogus PIDs
    if (pid < 0) {
        return 0;
    }

    hProcess = handle_from_pid(pid);
    if (NULL == hProcess) {
        //invalid parameter means PID isn't in the system
        if (GetLastError() == ERROR_INVALID_PARAMETER) { 
            return 0;
        }

        //some other error with OpenProcess
        return -1;
    }

    if (GetExitCodeProcess(hProcess, &exitCode)) {
        CloseHandle(hProcess);
        return (exitCode == STILL_ACTIVE);
    }

    //error in GetExitCodeProcess()
    CloseHandle(hProcess);
    return -1;
}

GetExitCodeProcess()最近停止したプロセスで成功するため、を使用する必要があることに注意してくださいOpenProcess()。有効なプロセスハンドルは、プロセスが実行中であることを意味するとは限りません。

OpenProcess()また、有効なPIDから3以内のPIDで成功することにも注意してください(プロセスIDに3を追加してもOpenProcessが成功する理由を参照してください) 。

于 2009-03-01T18:18:22.277 に答える
3

pid_exists 関数の使用には固有の競合状態があります。呼び出し側プログラムが応答を使用するようになるまでに、プロセスがすでに消滅しているか、照会された ID を持つ新しいプロセスが作成されている可能性があります。この関数を使用するアプリケーションには設計上の欠陥があり、この関数を最適化することは努力する価値がないとあえて言います。

于 2009-02-26T21:08:02.940 に答える
3

Jay の最後の関数をこのようにコーディングします。

int pid_is_running(DWORD pid){
    HANDLE hProcess;
    DWORD exitCode;
    //Special case for PID 0 System Idle Process
    if (pid == 0) {
        return 1;
    }
    //skip testing bogus PIDs
    if (pid < 0) {
        return 0;
    }
    hProcess = handle_from_pid(pid);
    if (NULL == hProcess) {
        //invalid parameter means PID isn't in the system
        if (GetLastError() == ERROR_INVALID_PARAMETER) {
             return 0;
        }
        //some other error with OpenProcess
        return -1;
    }
    DWORD dwRetval = WaitForSingleObject(hProcess, 0);
    CloseHandle(hProcess); // otherwise you'll be losing handles

    switch(dwRetval) {
    case WAIT_OBJECT_0;
        return 0;
    case WAIT_TIMEOUT;
        return 1;
    default:
        return -1;
    }
}

主な違いは、プロセス ハンドルのクローズ (この関数のクライアントが長時間実行されている場合に重要) とプロセス終了検出戦略です。WaitForSingleObject を使用すると、プロセスが終了するまでしばらく待つことができます (0 を関数パラメーター値に変更します)。

于 2009-03-04T02:13:18.093 に答える