¿Cuáles son las mejores prácticas para hacer que una aplicación brillante se ejecute más rápido?
shiny (1)
Esta es una pregunta muy interesante y merece más respuestas adecuadas que comentarios. Me gustaría relacionar mi experiencia y pensamientos. Construí una aplicación comercial R+shiny
con Shiny Server Pro, utilizando bases de datos y muchos otros trucos.
Tiempo de carga de UI retrasado
Mi aplicación tarda más de 30 segundos en cargarse, es decir, para devolverle el control al usuario.
La cuestión
Shiny
es una aplicación de una sola página. Por lo tanto, una aplicación compleja, con un montón de pestañas, datos cargados para llenar algunos de los menús y selectores, etc. se ve afectada y esto comienza desde el tiempo de carga inicial.
UI posibles mitigaciones
- Use componentes dinámicos de la interfaz de usuario (con inteligencia) para agregar complejidad después del inicio. Por ejemplo, un menú en particular puede comenzar muy simplemente con pocos elementos, luego agregar más elementos en una etapa posterior.
- Joe Cheng propuso
insertUI
yremoveUI
cuando mi aplicación estaba casi terminada, por lo que no logré usarlos, pero también podrían contribuir a una página más sencilla para comenzar.
Uso de la base de datos
Mi aplicación usaba MonetDB
y más tarde PostgreSQL
. El rendimiento de MonetDB
fue bueno, pero tuve un conflicto de usuarios múltiples (problema complejo que no puedo detallar aquí) y esto me obligó a cambiar a PostgreSQL
como alternativa. PostgreSQL
estaba bien, pero tomó un tiempo dramático para comenzar debido al problema de calentamiento de caché. El diseño requerido para cargar en el inicio un montón de datos en la base de datos: mal diseño.
RDBMS retrasa posibles mitigaciones
Creo que probé la mayoría de los trucos con éxito variable.
- Limitar el uso de RDBMS. Como decidí desde el principio usar
data.table
para acelerar las manipulaciones de datos sin restricciones de copia, también estaba usandofread
para cualquier tipo de lectura CSV. En el momento en quefwrite
(aún dedata.table
) ni siquiera estaba en el horizonte, de lo contrario merecería serias consideraciones. - Aplicación de rediseño. La arquitectura de la aplicación tiene mucho que ver con el grado de intensidad con el que se utilizan los RDBMS. Estoy convencido de que se puede ahorrar tiempo con un diseño que podría tener en cuenta las limitaciones de
R+shiny
(principalmenteR
). - Ahora,
MonetDB
tiene funcionesR
integradas en el código, por lo que debería ser incluso más rápido que antes. Sin duda merece un buen vistazo. Por otro lado, las funciones multiusuario deben probarse exhaustivamente: la mayoría del código de la base de datosR
no tiene en cuenta el uso en un entorno multiusuario como lo ofreceshiny
. Tal vezRStudio
debería estar haciendo algo más sobre esto. Sinceramente, ya han comenzado, con la introducción experimental deconnection pools
deconnection pools
y eso es genial.
Uso excesivo de la reactividad.
Creo que es genial jugar con un marco avanzado como shiny
, y la reactividad es muy divertida de aprender. Por otro lado, en una aplicación amplia y compleja, las cosas pueden fácilmente salirse de control.
Reactividad excesiva, posibles mitigaciones.
- La depuración de cada función da una idea precisa de la cantidad de veces que se llama una función
shiny
particular, y cualquier función reactiva se llama más de una vez. Por supuesto, todo esto quema el tiempo de la CPU, y necesita al menos mantenerlo bajo control. - Las construcciones como
observeEvent
ahora tienen parámetros comoignoreInit
: un uso inteligente de estos parámetros puede guardar al menos un ciclo de vacío en el momento de la inicialización.
En mi experiencia, solo hemos arañado la superficie de lo que es posible hacer con el shiny
. Por otro lado, hay un límite debido a la naturaleza del proceso único de R
Con Shiny Server Pro
es posible contemplar el uso de balanceadores de carga y la distribución de múltiples usuarios en diferentes servidores. Por otro lado, para entrar en estos territorios necesitaríamos algún tipo de sistema de mensajería en las distintas instancias. Ya sé que veo la necesidad de eso en las aplicaciones complejas de Shiny Server Pro
(por ejemplo, cuando existe la necesidad de administrar diferentes clases de usuarios, pero al mismo tiempo para comunicarse entre ellos). Pero esto está fuera del alcance de esta pregunta.
Datos:
Tengo una aplicación de panel brillante y mi conjunto de datos tiene un tamaño de alrededor de 600 MB. Se hincha por 100 MB cada mes. Mis datos residen localmente en MySQL.
Elementos de menú:
Tengo 6 - 7 elementos de menú de la barra lateral en mi panel y cada uno de ellos tiene 10 - 12 salidas diferentes: tablas y cuadros. Cada una de estas pestañas tiene de 3 a 6 entradas, como selectizeInput, control deslizante, rango de fechas, etc. para filtrar los datos.
Subconjuntos de datos:
Dado que no puedo cargar todos los datos en la memoria, para cada elemento del menú, creo un subconjunto de datos basados en el rango de fechas manteniendo el rango de fechas a tan solo 2 - 3 días desde la fecha del sistema.
Por ejemplo:
df1 <- reactive({df[df$date >- dateinput[1] & df$date <- dateinput[2], ]})
Lo anterior obtiene los datos para mi primer elemento de menú y, dependiendo de la entrada de selección u otras entradas, estoy filtrando aún más los datos. Por ejemplo, si tengo un selectInput para el Gender (male and female)
luego subconjunto df1
para:
df2 <- reactive({
if(is.null(input$Gender)){
df1
} else if(input$Gender == "Male")
{df1[df1$Gender == "Male",]}
)}
Si tengo más de 1 entrada, subjunto más este df1 y paso los valores a df2. df2 se convierte en el conjunto de datos reactivos de todos los cuadros y tablas en ese elemento de menú.
Cuanto mayor es el número de elementos de menú, más subconjuntos se crean para adaptarlos a los filtros y análisis.
Me enfrento a dos problemas:
- En máquinas antiguas, la aplicación no se está cargando. y
- En las máquinas más nuevas, la aplicación se carga muy lentamente a veces de 5 a 6 minutos
Después del primer conjunto de carga de datos, los cuadros y tablas se representan más rápido en los cambios reactivos.
Para contrarrestar esto, he intentado mover todos los parámetros y bibliotecas comunes y repetitivos a global.R.
Tengo dos preguntas:
1. hay algunos factores básicos de higiene que se deben tener en cuenta al extraer datos en R, especialmente a través de datos brillantes (la minería en R es extremadamente rápida).
2. He leído sobre el procesamiento en paralelo, pero casi siempre todos los ejemplos hablan de distribuir un solo cálculo más pesado. ¿Podemos distribuir a través del procesamiento en paralelo, la creación de subconjuntos de los datos o la distribución de la preparación de cuadros / tablas?
Tenga en cuenta que soy un investigador y no un programador, pero he aprendido a usar aplicaciones brillantes y host en la nube o localmente recientemente.
La orientación sobre esto será muy útil para muchos usuarios novatos de R como yo.