Un paquete Python para descargar una llamada de función a un servidor HTTP que se ejecuta en Localhost automáticamente usando un decorador. Compatible con el multiprocesamiento, Pickle, Flask, Fastapi, Async, etc.
Imagine un caso de una aplicación múltiple de múltiples roscas o multiprocesamiento donde 1 o pocas funciones son muy intensivas de recursos (CPU o memoria), pero las otras funciones pueden ejecutarse en paralelo.
Ejemplo: una llamada API seguida de tokenización y clasificación utilizando un modelo DL grande seguido de nuevas llamadas de API.
En tal caso, tendría sentido crear un servidor (generalmente usando antorchserve o TFServing) para satisfacer las solicitudes y reemplazar la llamada de función con una solicitud de publicación al servidor.
ServerHandler crea un servidor sincrónico y reemplaza cualquier llamada a la función automáticamente durante el tiempo de ejecución.
Las solicitudes se realizan a 1 instancia de un proceso que ejecuta un http.server.httpserver que ejecuta la función dentro de él.
AsyncServerHandler también está disponible, lo que hace las solicitudes de forma asincrónica.
Incluso las llamadas hechas de diferentes procesos, hilos, multiprocesamiento, frascos, fastapi y bucles de eventos Async se realizan en el mismo proceso del servidor.
En general :
some code with a callable
Se puede reemplazar con una instancia de ServerHandler o AsyncServerHandler que acepta el código como una cadena en su primer argumento y el nombre del llamable como el segundo argumento.
from auto_function_serving . ServerHandler import ServerHandler
callable_name = ServerHandler ( """
some independent code with a callable
""" , "callable_name" )Ejemplo :
import module1
import module2
def functionname ( someinput ):
a = module1 . function1 ( someinput )
return module2 . function2 ( a )se puede reemplazar con
from auto_function_serving . ServerHandler import AsyncserverHandler
functionname = AsyncServerHandler ( """
import module1
import module2
def functionname(someinput):
a = module1.function1(someinput)
return module2.function2(a)
""" , "functionname" , port = "Any" )Decoradores ( @asyncserverhandler.decorator y @serverhandler.decorator) y detalles de asyncserverhandler en más uso.
from auto_function_serving . ServerHandler import ServerHandler
callable_name = ServerHandler ( """
some independent code with a callable
""" , "callable_name" , port = None , backend = 'Popen' , wait = 100 , backlog = 1024 )) ejecuta http.server.httpserver.
Los objetos ServerHandler y AsyncServerHandler se pueden cargar y descargar con Pickle.
Utiliza popen o multiprocesamiento para ejecutar el servidor.
Utiliza solo una sola dependencia externa (AIOHTTP), y solo para Async.
http, no https.
Elige un puerto basado en el hash de entrada. (A menos que se especifique lo contrario)
Cambios de código mínimo.
Debe ser compatible con casi todas las funciones en casi todos los envs de Cpython. (¿No estoy seguro de dónde podría fallar? Agregue un problema si encuentra uno).
Las filtraciones o errores de memoria (del servidor) son extremadamente improbables, ya que es mínimo, un solo proceso de rosca, un solo componente predeterminado de Python Stdlib.
Las excepciones causan errores 5xx sin cerrar el servidor.
Incluso los procesos separados realizarán solicitudes a 1 instancia del mismo servidor a menos que se especifique lo contrario. (Porque está buscando un servidor en un puerto específico).
Puede especificar lo contrario establecer el puerto en cualquier puerto gratuito para que un nuevo objeto ServerHandler inicie un nuevo servidor.
Solicitudes de publicación HTTP: liviano, pocas MS Overhead, confiable.
Async es una buena característica.
ahora con pruebas.
Tener una cadena de código como argumento para una clase no es pitónico, a menos que se use el decorador.
Importar funciones interiores no es ideal, incluso cuando se usa el decorador.
Solicitudes de publicación HTTP: inseguro, pocas MS por encima.
No se envían excepciones dentro del servidor.
Sin lotes.
Sin registro incorporado. (Podría agregarse). Retraso de inicialización de hasta unos segundos para iniciar el servidor. Las funciones de Async no funcionarán en el servidor.
Ningún servidor automático se reinicia en Case Server cierra.
Puede dejar algunos recursos bloqueados por un tiempo (<1min) si no está cerrado correctamente.
Los problemas pueden ocurrir si Popen o el multiprocesamiento no están disponibles.
¿Posibles errores de asíncrono anidados con Jupyter u otro? Por favor, busque Nest-Asyncio y los problemas.
Advertencias de soluciones de soluciones algo hacky (pero legítimas y completamente funcionales).
El cierre del proceso del servidor en Del y Atexit.Redister ( DEL ) falla por alguna razón (probado y poco probable).
Utilice el PIP de Administrador de paquetes para instalar auto_function_serving
pip install auto_function_serving El código para el servidor se almacena en serverHandler.base_code y se utiliza algún formato de cadena para completar los espacios en blanco.
El proceso del servidor se inicia con Popen (o multiprocesamiento si se especifica). Lo primero que hace es importar el socket y unir el puerto; si no está disponible, el código se detiene después de una excepción. Por lo tanto, solo 1 instancia del servidor se ejecuta a la vez en una máquina.
Sabemos que la función está lista después de poder recibir una solicitud GET válida del servidor.
Las entradas y salidas se envían como bytes, convertidas hacia y desde objetos usando Pickle.
Si el puerto no está inicio durante la inicialización (predeterminada), se elige un puerto de 50000 a 60000 al hashing el código de entrada para que sea independiente de la fuente de una función. Las colisiones de diferentes funciones son posibles, pero poco probables. La colisión de la misma función en múltiples procesos se utiliza para asegurarse de que solo 1 proceso del servidor se ejecute a la vez. El puerto se puede especificar si es necesario.
sobrecarga para pequeñas entradas y salida (pocos bytes) -
~ 2 ms para solicitudes con urllib.request
~ 4ms para solicitudes de async con aiohttp.clientsession
sobrecarga para grandes entradas y salida
~ 10 ms para entrada y salida de 0.5 Mb (transferencia total de 1 MB).
~ 60 ms para entrada y salida de 5 MB (transferencia total de 10 MB).
~ 600 ms para entrada y salida de 50 MB (transferencia total de 100 MB).
También se puede usar con el decorador proporcionado para funciones sin dependencias fuera de la función.
from auto_function_serving . ServerHandler import ServerHandler
@ ServerHandler . decorator
def someheavyfunction ( args , ** kwargs ):
for i in range ( big_number )
someexpensivecomputationLas importaciones dentro de la función funcionarán
from auto_function_serving . ServerHandler import ServerHandler
@ ServerHandler . decorator
def someheavyfunction ( args , ** kwargs ):
import numpy as np from auto_function_serving . ServerHandler import ServerHandler
@ ServerHandler . decorator
def someheavyfunction ( args , ** kwargs ):
if not hasattr ( someheavyfunction , 'RunOnce' ):
global np
import numpy as np
setattr ( someheavyfunction , 'RunOnce' , None )
... etcCuando el SomEmodule no tiene una carga global costosa.
from auto_function_serving . ServerHandler import ServerHandler
from somemodule import someheavyfunction
someheavyfunction = ServerHandler . decorator ( someheavyfunction )La dirección IP se puede cambiar configurando serverHandler.ip_address (predeterminado "127.0.0.1") antes de crear una nueva instancia.
AsyncServerHandler también está disponible, que utiliza AIOHTTP para hacer las solicitudes de forma asincrónica, para usar con FastAPI y otros casos de uso de Async.
AsyncServerHandler tiene el mismo uso que ServerHandler, excepto que las llamadas deben esperar o usarse con asyncio.run () o con asyncio.get_event_loop (). Run_until_complete ().
El número de llamadas de async puede limitarse configurando asyncserverhandler.tcpconnector_limit que controla el límite TCPConnector (predeterminado 100). Usar semáforo también es algo a considerar.
Bibliotecas: Celery, TFServing, Torchserve, Flask
Enviar globales y locales a ejecutarse
árboles
Las solicitudes de extracción son bienvenidas.
Licencia de Apache 2.0