MCP HubMCP Hub
스킬 목록으로 돌아가기

optimize-shiny-performance

pjt222
업데이트됨 2 days ago
7 조회
17
2
17
GitHub에서 보기
기타general

정보

이 스킬은 profvis, bindCache, memoise, async/promises 같은 도구를 사용하여 Shiny 앱의 성능을 분석하고 최적화합니다. 앱이 느리게 느껴질 때, 부하 상황에서 서버 자원이 부족할 때, 또는 특정 작업이 병목 현상을 일으킬 때 사용하도록 설계되었습니다. 많은 동시 사용자를 위한 프로덕션 환경 배포를 준비하는 데 활용하세요.

빠른 설치

Claude Code

추천
기본
npx skills add pjt222/agent-almanac -a claude-code
플러그인 명령대체
/plugin add https://github.com/pjt222/agent-almanac
Git 클론대체
git clone https://github.com/pjt222/agent-almanac.git ~/.claude/skills/optimize-shiny-performance

Claude Code에서 이 명령을 복사하여 붙여넣어 스킬을 설치하세요

문서


name: optimize-shiny-performance description: > Perfilar y optimizar el rendimiento de aplicaciones Shiny usando profvis, bindCache, memoise, async/promises, debounce/throttle y ExtendedTask para computaciones de larga duración. Úsalo cuando la app se siente lenta o no responde durante la interacción del usuario, cuando los recursos del servidor se agotan bajo carga concurrente, cuando operaciones específicas crean cuellos de botella, o al preparar una app para despliegue en producción con muchos usuarios concurrentes. locale: es source_locale: en source_commit: 6f65f316 translator: claude-opus-4-6 translation_date: 2026-03-16 license: MIT allowed-tools: Read Write Edit Bash Grep Glob metadata: author: Philipp Thoss version: "1.0" domain: shiny complexity: advanced language: R tags: shiny, performance, profiling, caching, async, promises, optimization

Optimize Shiny Performance

Perfilar, diagnosticar y optimizar el rendimiento de aplicaciones Shiny mediante caché, operaciones async y optimización del grafo reactivo.

Cuándo Usar

  • La app Shiny se siente lenta o no responde durante la interacción del usuario
  • Los recursos del servidor se agotan bajo carga de usuarios concurrentes
  • Operaciones específicas (carga de datos, gráficos, computación) crean cuellos de botella
  • Al preparar una app para despliegue en producción con muchos usuarios

Entradas

  • Requerido: Ruta a la aplicación Shiny
  • Requerido: Descripción del problema de rendimiento (carga lenta, interacción lenta, memoria alta)
  • Opcional: Número de usuarios concurrentes esperados
  • Opcional: Recursos disponibles del servidor (RAM, núcleos CPU)
  • Opcional: Si la app usa una base de datos o API externa

Procedimiento

Paso 1: Perfilar la Aplicación

# Perfilar con profvis
profvis::profvis({
  shiny::runApp("path/to/app", display.mode = "normal")
})

# O perfilar operaciones específicas
profvis::profvis({
  result <- expensive_computation(data)
})

Identifica los principales cuellos de botella:

  1. Carga de datos: ¿Cuánto tarda la recuperación inicial de datos?
  2. Recalculación reactiva: ¿Qué reactivos se activan con más frecuencia?
  3. Renderizado: ¿Qué salidas tardan más en renderizarse?
  4. Llamadas externas: ¿Consultas de base de datos, solicitudes de API, E/S de archivos?

Usa el registro reactivo para análisis del grafo reactivo:

# Habilitar el registro reactivo
options(shiny.reactlog = TRUE)
shiny::runApp("path/to/app")
# Presiona Ctrl+F3 en el navegador para ver el grafo reactivo

Esperado: Identificación clara de los 2-3 mayores cuellos de botella.

En caso de fallo: Si profvis no muestra detalles útiles, envuelve secciones específicas con profvis::profvis(). Si reactlog es abrumador, céntrate en una interacción a la vez.

Paso 2: Optimizar el Grafo Reactivo

Reduce las invalidaciones reactivas innecesarias:

# MAL: Recalcula con CUALQUIER cambio de entrada
output$plot <- renderPlot({
  data <- load_data()  # Se ejecuta cada vez
  filtered <- data[data$category == input$category, ]
  plot(filtered)
})

# BIEN: Aislar la carga de datos del filtrado
raw_data <- reactive({
  load_data()
}) |> bindCache()  # Cachear la parte costosa

filtered_data <- reactive({
  raw_data()[raw_data()$category == input$category, ]
})

output$plot <- renderPlot({
  plot(filtered_data())
})

Usa isolate() para prevenir invalidaciones innecesarias:

# Solo recalcula cuando se hace clic en el botón, no con cada cambio de entrada
output$result <- renderText({
  input$compute  # Tomar dependencia del botón
  isolate({
    paste("N =", input$n, "Mean =", mean(rnorm(input$n)))
  })
})

Usa debounce() y throttle() para entradas de alta frecuencia:

# Debounce de entrada de texto — esperar 500ms después de que el usuario deje de escribir
search_text <- reactive(input$search) |> debounce(500)

# Throttle del slider — actualizar como máximo cada 250ms
slider_value <- reactive(input$slider) |> throttle(250)

Esperado: El grafo reactivo solo activa los recálculos necesarios.

En caso de fallo: Si eliminar una dependencia rompe la funcionalidad, usa req() para añadir guardas explícitas en lugar de depender de dependencias reactivas implícitas.

Paso 3: Implementar Caché

bindCache para Salidas Shiny

output$plot <- renderPlot({
  create_expensive_plot(filtered_data())
}) |> bindCache(input$category, input$date_range)

output$table <- renderDT({
  expensive_query(input$filters)
}) |> bindCache(input$filters)

bindCache usa los valores de entrada como claves de caché. Cuando las mismas entradas ocurren de nuevo, el resultado en caché se devuelve inmediatamente.

memoise para Funciones

# Cachear resultados de funciones costosas
load_reference_data <- memoise::memoise(
  function(dataset_name) {
    readr::read_csv(paste0("data/", dataset_name, ".csv"))
  },
  cache = cachem::cache_disk("cache/", max_age = 3600)
)

Pre-computación de Datos a Nivel de App

# En global.R o fuera de la función server — computado una vez al iniciar la app
reference_data <- readr::read_csv("data/reference.csv")
model <- readRDS("models/trained_model.rds")

server <- function(input, output, session) {
  # reference_data y model están disponibles para todas las sesiones
  # sin volver a cargar
}

Esperado: Las operaciones repetidas usan resultados en caché; el tiempo de respuesta cae significativamente.

En caso de fallo: Si la caché crece demasiado, establece límites max_age o max_size. Si los valores en caché son obsoletos, reduce max_age o añade un botón para limpiar la caché. Si bindCache causa errores, asegúrate de que las entradas de la clave de caché sean serializables.

Paso 4: Añadir Async para Operaciones Largas

Usa ExtendedTask (Shiny >= 1.8.1) para computaciones de larga duración:

server <- function(input, output, session) {
  # Definir la tarea extendida
  analysis_task <- ExtendedTask$new(function(data, params) {
    promises::future_promise({
      # Esto se ejecuta en un proceso en segundo plano
      run_heavy_analysis(data, params)
    })
  }) |> bind_task_button("run_analysis")

  # Activar la tarea
  observeEvent(input$run_analysis, {
    analysis_task$invoke(dataset(), input$params)
  })

  # Usar el resultado
  output$result <- renderTable({
    analysis_task$result()
  })
}

Para apps en Shiny < 1.8.1, usa promises directamente:

library(promises)
library(future)
plan(multisession, workers = 4)

server <- function(input, output, session) {
  result <- eventReactive(input$compute, {
    future_promise({
      Sys.sleep(5)  # Simular computación larga
      expensive_analysis(isolate(input$params))
    })
  })

  output$table <- renderTable({
    result()
  })
}

Esperado: Las operaciones largas no bloquean la UI; otros usuarios pueden interactuar mientras la computación se ejecuta.

En caso de fallo: Si future_promise da error, verifica que plan(multisession) esté configurado. Si las variables no están disponibles en el futuro, pásalas explícitamente — los futuros se ejecutan en procesos R separados.

Paso 5: Optimizar el Renderizado

Reduce la sobrecarga de renderizado:

# Usar plotly para gráficos interactivos en lugar de volver a renderizar
output$plot <- plotly::renderPlotly({
  plotly::plot_ly(filtered_data(), x = ~x, y = ~y, type = "scatter")
})

# Usar DT del lado del servidor para tablas grandes
output$table <- DT::renderDataTable({
  DT::datatable(large_data(), server = TRUE, options = list(
    pageLength = 25,
    processing = TRUE
  ))
})

# UI condicional para evitar renderizar elementos ocultos
output$details <- renderUI({
  req(input$show_details)
  expensive_details_ui()
})

Esperado: Las operaciones de renderizado son más rápidas y no bloquean la UI.

En caso de fallo: Si plotly es lento con conjuntos de datos grandes, usa toWebGL() para renderizado WebGL o reduce la muestra de datos antes de graficar.

Paso 6: Validar las Mejoras de Rendimiento

# Benchmarking antes/después
system.time({
  shiny::testServer(myModuleServer, args = list(...), {
    session$setInputs(category = "A")
    session$flushReact()
  })
})

# Pruebas de carga con shinyloadtest
shinyloadtest::record_session("http://localhost:3838")
shinyloadtest::shinycannon(
  "recording.log",
  "http://localhost:3838",
  workers = 10,
  loaded_duration_minutes = 5
)
shinyloadtest::shinyloadtest_report("recording.log")

Esperado: Mejora medible en los tiempos de respuesta y/o capacidad de usuarios concurrentes.

En caso de fallo: Si el rendimiento no mejoró, vuelve a perfilar para encontrar el siguiente cuello de botella. La optimización del rendimiento es iterativa — corrige primero el mayor cuello de botella y luego vuelve a medir.

Validación

  • El perfilado identifica cuellos de botella específicos (sin suposiciones)
  • El grafo reactivo no tiene cadenas de invalidación innecesarias
  • Las operaciones costosas usan caché (bindCache o memoise)
  • Las computaciones de larga duración usan async (ExtendedTask o promises)
  • Las entradas de alta frecuencia usan debounce/throttle
  • Los conjuntos de datos grandes usan procesamiento del lado del servidor
  • La mejora del rendimiento es medible (tiempos antes/después)

Errores Comunes

  • Optimización prematura: Perfila primero. El cuello de botella raramente está donde crees.
  • Bugs de invalidación de caché: Si los usuarios ven datos obsoletos, la clave de caché no incluye todas las entradas relevantes. Añade las dependencias faltantes a bindCache().
  • Alcance de variables en futuros: future_promise se ejecuta en un proceso separado. Las variables globales, conexiones de base de datos y valores reactivos deben capturarse explícitamente.
  • Espagueti reactivo: Si el grafo reactivo es demasiado complejo para entender, la app necesita refactorización arquitectural (módulos), no solo caché.
  • Sobre-cachear: Cachear todo desperdicia memoria. Solo cachea operaciones que son costosas Y tienen patrones de entrada repetidos.

Habilidades Relacionadas

  • build-shiny-module — arquitectura modular para código reactivo mantenible
  • scaffold-shiny-app — elegir el framework correcto de la app desde el inicio
  • deploy-shiny-app — desplegar apps optimizadas con recursos de servidor apropiados
  • test-shiny-app — tests de regresión de rendimiento

GitHub 저장소

pjt222/agent-almanac
경로: i18n/es/skills/optimize-shiny-performance
0
agentsagentskillsai-assisted-developmentclaude-codeskillsteams

연관 스킬

llamaguard

기타

LlamaGuard는 폭력 및 혐오 발언 등 6가지 안전 범주에서 LLM 입력과 출력을 조정하기 위한 Meta의 70-80억 파라미터 모델입니다. 94-95% 정확도를 제공하며 vLLM, Hugging Face 또는 Amazon SageMaker를 사용해 배포할 수 있습니다. 이 기술을 사용하여 AI 애플리케이션에 콘텐츠 필터링 및 안전 가드레일을 손쉽게 통합하세요.

스킬 보기

cost-optimization

기타

이 Claude Skill은 리소스 적정화, 태깅 전략, 지출 분석을 통해 개발자들이 클라우드 비용을 최적화할 수 있도록 지원합니다. AWS, Azure, GCP에서 클라우드 비용을 절감하고 비용 거버넌스를 구현하기 위한 프레임워크를 제공합니다. 인프라 비용을 분석하거나, 리소스를 적정화하거나, 예산 제약을 충족해야 할 때 사용하세요.

스킬 보기

quantizing-models-bitsandbytes

기타

이 스킬은 bitsandbytes를 사용하여 LLM을 8비트 또는 4비트 정밀도로 양자화하며, 최소한의 정확도 손실로 50-75%의 메모리 감소를 달성합니다. 제한된 GPU 메모리에서 더 큰 모델을 실행하거나 추론을 가속화하는 데 이상적이며, INT8, NF4, FP4와 같은 형식을 지원합니다. 이 스킬은 HuggingFace Transformers와 통합되어 QLoRA 학습 및 8비트 옵티마이저를 가능하게 합니다.

스킬 보기

dispatching-parallel-agents

기타

이 Claude Skill은 3개 이상의 독립적인 문제를 동시에 조사하고 해결하기 위해 다중 에이전트를 배치합니다. 공유 상태나 의존성 없이 해결 가능한 무관련 장애 시나리오에 맞게 설계되었습니다. 핵심 기능은 병렬 문제 해결로, 각 독립 문제 영역마다 하나의 에이전트를 할당하여 효율성을 극대화합니다.

스킬 보기