tiempo tarea script programada hora funcion ejecutar desde consola codigo cierto cada automaticamente archivo python time

tarea - El tiempo de ejecución del script de Python aumenta cuando se ejecuta varias veces en paralelo



ejecutar.py desde consola python (5)

Tengo un script de python cuyo tiempo de ejecución es de 1.2 segundos mientras se ejecuta de forma independiente.

Pero cuando lo ejecuto 5-6 veces en forma paralela (estoy usando el cartero para hacer ping en la url varias veces), el tiempo de ejecución se dispara.

Agregando el desglose del tiempo tomado.

1 run -> ~1.2seconds 2 run -> ~1.8seconds 3 run -> ~2.3seconds 4 run -> ~2.9seconds 5 run -> ~4.0seconds 6 run -> ~4.5seconds 7 run -> ~5.2seconds 8 run -> ~5.2seconds 9 run -> ~6.4seconds 10 run -> ~7.1seconds

Captura de pantalla del comando superior (Preguntado en el comentario):

Este es un código de muestra:

import psutil import os import time start_time = time.time() import cgitb cgitb.enable() import numpy as np import MySQLdb as mysql import cv2 import sys import rpy2.robjects as robj import rpy2.robjects.numpy2ri rpy2.robjects.numpy2ri.activate() from rpy2.robjects.packages import importr R = robj.r DTW = importr(''dtw'') process= psutil.Process(os.getpid()) print " Memory Consumed after libraries load: " print process.memory_info()[0]/float(2**20) st_pt=4 # Generate our data (numpy arrays) template = np.array([range(84),range(84),range(84)]).transpose() query = np.array([range(2500000),range(2500000),range(2500000)]).transpose() #time taken print(" --- %s seconds ---" % (time.time() - start_time))

También verifiqué el consumo de memoria con el watch -n 1 free -m y el consumo de memoria también aumenta notablemente.

1) ¿Cómo me aseguro de que el tiempo de ejecución del script permanezca constante cada vez?

2) ¿Puedo cargar las bibliotecas permanentemente para minimizar el tiempo que toma la secuencia de comandos para cargar las bibliotecas y la memoria consumida?

Hice un entorno y traté de usar

#!/home/ec2-user/anaconda/envs/test_python/

pero no hace ninguna diferencia en absoluto.

EDITAR:

Tengo el servidor EC2 de AMAZON con 7,5 GB de RAM.

Mi archivo php con el que estoy llamando a la secuencia de comandos python.

<?php $response = array("error" => FALSE); if($_SERVER[''REQUEST_METHOD'']==''GET''){ $response["error"] = FALSE; $command =escapeshellcmd(shell_exec("sudo /home/ec2-user/anaconda/envs/anubhaw_python/bin/python2.7 /var/www/cgi-bin/dtw_test_code.py")); session_write_close(); $order=array("/n","//"); $cleanData=str_replace($order,'''',$command); $response["message"]=$cleanData; } else { header(''HTTP/1.0 400 Bad Request''); $response["message"] = "Bad Request."; } echo json_encode($response); ?>

Gracias


La nube ec2 no garantiza 7.5gb de memoria libre en el servidor. Esto significaría que el rendimiento de la VM se verá gravemente afectado, como si estuviese viendo que el servidor tiene menos de 7.5 gb de ram físico libre. Intente reducir la cantidad de memoria que el servidor cree que tiene.

Esta forma de ejecución paralela es muy costosa. Típicamente, con un requisito de 300mb, lo ideal sería un script que se ejecute durante mucho tiempo, y reutilice la memoria para múltiples solicitudes. La función de bifurcación de Unix permite reutilizar un estado compartido. El os.fork da esto en python, pero puede no ser compatible con sus bibliotecas.


1)

Más servidores equivalen a más disponibilidad

Los rumores me dicen que una forma efectiva de garantizar tiempos de solicitud consistentes es usar múltiples solicitudes a un clúster. Según lo escuché, la idea es algo como esto.

La posibilidad de una solicitud lenta

(Descargo de responsabilidad No soy mucho matemático o estadístico).

Si hay un 1% de probabilidad de que una solicitud tarde un tiempo anormal en finalizar, se puede esperar que una de cada cien solicitudes sea lenta. Si usted, como cliente / consumidor, realiza dos solicitudes a un clúster en lugar de solo una, la probabilidad de que ambas resulten lentas sería más bien 1/10000, y con tres 1/1000000, etcétera. La desventaja es duplicar sus solicitudes entrantes significa que necesita proporcionar (y pagar) hasta el doble de la potencia del servidor para cumplir sus solicitudes con un tiempo constante, este costo adicional aumenta con la cantidad de posibilidades aceptables para una solicitud lenta.

Que yo sepa este concepto está optimizado para tiempos de cumplimiento consistentes.

El cliente

Un cliente que interactúa con un servicio como este tiene que poder generar múltiples solicitudes y manejarlas correctamente, lo que probablemente incluye el cierre de las conexiones no realizadas tan pronto como sea posible.

Los servidores

En el respaldo, debe haber un equilibrador de carga que pueda asociar múltiples solicitudes de clientes entrantes a múltiples trabajadores únicos del clúster. Si un solo cliente realiza múltiples solicitudes a un nodo sobrecargado, solo va a acumular su propio tiempo de solicitud como ve en su ejemplo simple.

Además de tener conexiones cercanas de manera oportunista con el cliente, lo mejor sería contar con un sistema para compartir el estado / información del trabajo, de modo que la solicitud atrasada en otros nodos más lentos de procesar tenga la posibilidad de abortar una solicitud ya cumplida.

Esta es una respuesta bastante informal, no tengo experiencia directa con la optimización de una aplicación de servicio de esta manera. Si alguien lo hace, animo y acepto modificaciones más detalladas y opiniones de implementación de expertos.

2)

Las importaciones de caché

sí, eso es una cosa, ¡y es increíble!

Yo personalmente recomendaría configurar django + gunicorn + nginx. Nginx puede almacenar en caché el contenido estático y mantener un registro de solicitudes, gunicorn proporciona almacenamiento en caché de aplicaciones y gestión de múltiples hilos y trabajadores (sin mencionar las asombrosas herramientas de administración y estadísticas), django incorpora las mejores prácticas para migraciones de bases de datos, autenticación, enrutamiento de solicitudes, así como Complementos de estantería para proporcionar puntos finales semánticos de descanso y documentación, todo tipo de bondades.

Si realmente insistes en construirlo desde cero, debes estudiar uWsgi , una gran implementación de Wsgi que se puede interconectar con gunicorn para proporcionar el almacenamiento en caché de aplicaciones. Gunicorn no es la única opción, Nicholas Piël tiene un gran artículo que compara el rendimiento de varias aplicaciones de servidor web de Python.


Esto es lo que tenemos:

  • El tipo de instancia EC2 es el cuadro m3.large que tiene solo 2 vCPU https://aws.amazon.com/ec2/instance-types/?nc1=h_ls

  • Necesitamos ejecutar una secuencia de comandos que consuma CPU y memoria, que tarda más de un segundo en ejecutarse cuando la CPU no está ocupada.

  • Está creando una API que necesita manejar solicitudes concurrentes y ejecutar apache

  • De la captura de pantalla puedo concluir que:

    • sus CPU se utilizan al 100% cuando se ejecutan 5 procesos. Lo más probable es que se utilicen al 100% incluso cuando se ejecutan menos procesos. Así que este es el cuello de botella y no es de extrañar que cuantos más procesos se ejecuten, más tiempo se requiere: los recursos de la CPU se comparten entre los scripts que se ejecutan simultáneamente.

    • cada copia de script consume aproximadamente ~ 300MB de RAM, por lo que tiene mucha RAM libre y no es un cuello de botella. La cantidad de memoria libre + buffers en su captura de pantalla lo confirma.

  • La parte faltante es:

    1. ¿Las solicitudes se envían directamente a su servidor apache o hay un equilibrador / proxy en frente de él?
    2. ¿Por qué necesitas PHP en tu ejemplo? Hay muchas soluciones disponibles usando el ecosistema de Python solo sin una envoltura de php delante de ella

Respuestas a tus preguntas:

  1. Eso es inviable en el caso general

Lo máximo que puede hacer es rastrear el uso de su CPU y asegurarse de que su tiempo de inactividad no caiga por debajo de un umbral empírico; en este caso, sus scripts se ejecutarán en un período de tiempo más o menos fijo.

Para garantizar que necesita limitar el número de solicitudes que se procesan al mismo tiempo. ¡Pero si 100 solicitudes se envían a su API al mismo tiempo, no podrá gestionarlas todas en paralelo! Solo algunos de ellos se manejarán en paralelo mientras otros esperan su turno. Pero su servidor no será derribado tratando de servirlos a todos.

  1. si y no

No porque es poco probable que pueda hacer algo en su arquitectura actual cuando se inicia un nuevo script en cada solicitud a través de un contenedor php. Por cierto, es una operación muy costosa ejecutar un nuevo script desde cero cada vez.

Sí, si se usa una solución diferente. Estas son las opciones:

  • utilice un servidor web pre-bifurcación compatible con python que gestionará sus solicitudes directamente. Ahorrará recursos de CPU en el inicio de python + puede utilizar algunas técnicas de precarga para compartir RAM entre los trabajadores, es decir, http://docs.gunicorn.org/en/stable/settings.html#preload-app . También necesitaría limitar la cantidad de trabajadores paralelos que se ejecutarán en http://docs.gunicorn.org/en/stable/settings.html#workers para cumplir con su primer requisito.

  • si necesita PHP por algún motivo, puede configurar algún intermediario entre el script PHP y los trabajadores de Python, es decir, un servidor tipo cola . Simplemente ejecute varias instancias de sus scripts de Python que esperarían a que alguna solicitud esté disponible en la cola. Una vez que esté disponible, lo manejaría y devolvería la respuesta a la cola y el script php lo sorbería y lo devolvería al cliente. Pero es más complejo construir esto que la primera solución (si puedes eliminar tu script PHP por supuesto) y más componentes estarían involucrados.

  • rechace la idea de manejar esas pesadas solicitudes al mismo tiempo, y en su lugar asigne a cada solicitud un ID único , coloque la solicitud en una cola y devuelva este ID al cliente de inmediato. Un controlador fuera de línea recogerá la solicitud y la pondrá de nuevo en la cola una vez que haya finalizado. Será responsabilidad del cliente sondear su API para la preparación de esta solicitud en particular

  • 1 ° y 2 ° combinado - maneje solicitudes en PHP y solicite otro servidor HTTP (o cualquier otro servidor TCP) que maneje sus scripts .py precargados.


Puede deberse a la forma en que se ejecutan las computadoras.

Cada programa recibe un trozo de tiempo en una computadora (cite Help Your Kids with Computer Programming , digamos 1/1000 de segundo )

Respuesta 1 : intente utilizar múltiples hilos en lugar de procesos paralelos .

Tomará menos tiempo , pero el tiempo de ejecución del programa aún no será completamente constante .

Nota: Cada programa tiene su propia ranura de memoria , por lo que es por eso que el consumo de memoria se dispara.


1) Realmente no puedes asegurarte de que la ejecución tomará siempre el mismo tiempo, pero al menos puedes evitar la degradación del rendimiento usando una estrategia de "bloqueo" como las descritas en esta respuesta .

Básicamente puede probar si el archivo de bloqueo existe, y si es así, ponga su programa a dormir una cierta cantidad de tiempo, luego intente de nuevo.

Si el programa no encuentra el archivo de bloqueo, lo crea y elimina el archivo de bloqueo al final de su ejecución.

Tenga en cuenta: en el siguiente código, cuando la secuencia de comandos no obtiene el bloqueo para un cierto número de retries , se cerrará (pero esta elección depende de usted).

El siguiente código ejemplifica el uso de un archivo como un "bloqueo" contra ejecuciones paralelas del mismo script.

import time import os import sys lockfilename = ''.lock'' retries = 10 fail = True for i in range(retries): try: lock = open(lockfilename, ''r'') lock.close() time.sleep(1) except Exception: print(''Got after {} retries''.format(i)) fail = False lock = open(lockfilename, ''w'') lock.write(''Locked!'') lock.close() break if fail: print("Cannot get the lock, exiting.") sys.exit(2) # program execution... time.sleep(5) # end of program execution os.remove(lockfilename)

2) Esto significaría que diferentes instancias de python compartirían el mismo conjunto de memoria y creo que no es factible.