Pregunta

Me doy cuenta de "rápida" es un poco subjetivo por lo que voy a explicar con un poco de contexto. Estoy trabajando en un módulo de Python llamada psutil para la lectura procesar la información de manera multiplataforma. Una de las funciones es una función pid_exists(pid) para determinar si un PID está en la lista proceso actual.

En este momento estoy haciendo esto la manera obvia, usando EnumProcesses () para tirar de la lista de procesos, a continuación, interating por la lista y buscar el PID. Sin embargo, algunos de evaluación comparativa sencilla muestra esto es dramáticamente más lento que la función pid_exists en plataformas basadas en UNIX (Linux, OS X, FreeBSD) en el que estamos utilizando kill(pid, 0) con una señal de 0 a determinar si existe un PID. Las pruebas adicionales se le notan los EnumProcesses que está ocupando casi todo el tiempo.

Alguien sabe de una manera más rápida que usando EnumProcesses para determinar si existe un PID? Probé OpenProcess () y la comprobación de una error al abrir el proceso inexistente, pero esto resultó ser más de 4 veces más lenta que la iteración a través de la lista EnumProcesses, por lo que está fuera así. Cualquier otro (mejor) sugerencias?

Nota: : Esta es una biblioteca de Python destinado a evitar terceros dependencias de bibliotecas como extensiones pywin32. Necesito una solución que es más rápido que nuestro código actual, y que no depende de pywin32 u otros módulos que no están presentes en una distribución estándar de Python.

Editar : Para aclarar - estamos muy conscientes de que existen condiciones de carrera inherentes a la lectura iformation proceso. Elevamos excepciones si el proceso desaparece durante el curso de la recopilación de datos o nos encontramos con otros problemas. Los pid_exists () no está destinado a sustituir manejo de errores adecuado.

Actualizar : Al parecer mis puntos de referencia anteriores eran defectuosos - escribí algunas aplicaciones de pruebas simples en C y EnumProcesses viene consistentemente más lento y OpenProcess (en conjunción con GetProcessExitCode en caso de que el PID es válido, pero el proceso tiene detenido) es en realidad mucho rápido no más lento.

¿Fue útil?

Solución

OpenProcess podría decirle w / o enumerando todos. No tengo idea de qué tan rápido.

Editar . En cuenta que también necesita GetExitCodeProcess para verificar el estado del proceso, incluso si se obtiene un mango de OpenProcess

Otros consejos

Hay una condición de carrera inherentes a la utilización de la función pid_exists: en el momento en el programa llamando llega a utilizar la respuesta, el proceso puede ya han desaparecido, o un nuevo proceso con el id consultada pueden haber sido creados. Me atrevería a decir que cualquier aplicación que utiliza esta función está viciado por el diseño y la optimización de esta función que, por tanto, no vale la pena el esfuerzo.

Resulta que mis puntos de referencia, evidentemente, eran defectuosos de alguna manera, como la prueba más tarde revela OpenProcess y GetExitCodeProcess son mucho más rápido que usar EnumProcesses después de todo. No estoy seguro de lo que pasó, pero hice algunas nuevas pruebas y verificado esta es la solución más rápida:

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;
}

Tenga en cuenta que es necesario utilizar GetExitCodeProcess() porque OpenProcess() tendrá éxito en los procesos que han muerto recientemente, por lo que no puede asumir un identificador de proceso válida significa que el proceso está en marcha.

Tenga en cuenta también que OpenProcess() tiene éxito para los PID que están a menos de 3 de cualquier ID de producto válido (consulte ¿Por qué OpenProcess tener éxito incluso cuando agrego tres para el ID de proceso? )

Me último código de la función de Jay de esta manera.

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;
    }
}

La diferencia principal está cerrando el identificador de proceso (importante cuando el cliente de esta función se está ejecutando desde hace mucho tiempo) y la estrategia de detección de la terminación del proceso. WaitForSingleObject le da la oportunidad de esperar por un tiempo (cambio del 0 a un valor de parámetro de función) hasta que termine el proceso.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top