Блестящий сеанс R с несколькими подключенными пользователями

Минимальный воспроизводимый пример:

library("shiny")

ui <- fluidPage(
  actionButton("button1", "Run 1"),
  actionButton("button2", "Run 2")
)

server <- function(session, input, output) {
  cat("session starts\n")
  observeEvent(input$button1, {
    cat("1 starts\n")
    Sys.sleep(15)
    cat("1 stops\n")
  })

  observeEvent(input$button2, {
    cat("2 starts\n")
    Sys.sleep(15)
    cat("2 stops\n")
  })
}

shinyApp(ui = ui, server = server)

Каждая кнопка имитирует выполнение некоторого длительного алгоритма с интенсивным использованием ЦП.

  1. Запустите приложение и откройте сеанс на одной вкладке браузера.
  2. Откройте другую вкладку браузера с другим сеансом для работающего приложения.
  3. Запустите Выполнить 1 на первой вкладке. Перейдите на вторую вкладку браузера и запустите Выполнить 2.

Проблема: вторая кнопка-обозреватель не запускается самостоятельно. Он ожидает завершения первого запуска в первом сеансе. Я думал, что блестящие сеансы независимы. Как shiny обрабатывает несколько сеансов Shiny за один сеанс R? Что делать, если к приложению одновременно хотят подключиться несколько пользователей?

Как справиться с тем, что несколько пользователей одновременно запускают одно и то же приложение? Спасибо


person JonnyRobbie    schedule 10.03.2020    source источник
comment
R является однопоточным, поэтому запросы по умолчанию будут помещены в очередь. Команда Shiny представила пакеты promises и futures, позволяющие пользователям выполнять async операции rstudio.github.io /promises/articles/shiny.html   -  person Pork Chop    schedule 10.03.2020
comment
Думаю, это единственное решение, которое я вижу. Я просто подумал, что shiny по своей сути использует один из этих пакетов парралелизации для обработки нескольких сеансов. Возникает вопрос: можно ли использовать пакет future, чтобы обернуть всю функцию сервера в одно обещание?   -  person JonnyRobbie    schedule 10.03.2020
comment
Не стоит недооценивать преимущества однопоточных приложений, здесь гораздо меньше поводов для беспокойства. Узел, бэкэнд shiny, является однопоточным, однако он может легко поддерживать 50 тысяч одновременных пользователей в любой момент времени. Что касается использования обещаний на сервере, краткий ответ, вероятно, отрицательный. Если вы хотите обернуть приложение в отдельное приложение, загляните в докер shinyproxy.io   -  person Pork Chop    schedule 10.03.2020
comment
У нас есть функции машинного обучения, которые могут занять до нескольких десятков минут. Я знал, что R является однопоточным, но, как я уже сказал, я предположил (ошибочно - мое плохое), что shiny идет параллельно.   -  person JonnyRobbie    schedule 10.03.2020


Ответы (1)


Ограничьте количество подключений к одному рабочему процессу, т. Е. Дайте каждому пользователю собственный рабочий процесс R. Вы можете сделать это, установив количество одновременных подключений, разрешенных для одного рабочего процесса, равным 1.

Если вы развертываете свое приложение через shinyapps.io, инструкции и дополнительная информация находятся здесь: https://shiny.rstudio.com/articles/scaling-and-tuning.html

Если вы выполняете развертывание на своем собственном блестящем сервере, инструкции и дополнительная информация находятся здесь: https://support.rstudio.com/hc/en-us/articles/220546267-Scaling-and-Performance-Tuning-Applications-in-Shiny-Server-Pro

Я взял ваше приложение, добавил видимый индикатор выполнения и развернул его с указанными выше настройками: https://minhealthnz.shinyapps.io/example_parallel/

library("shiny")

ui <- fluidPage(
  actionButton("button1", "Run 1"),
  actionButton("button2", "Run 2")
)

server <- function(session, input, output) {

  observeEvent(input$button1, {

    withProgress(message = 'Run 1', detail = '', value = 0, {
        for (i in 1:15) {
            incProgress(1/15)
            Sys.sleep(0.25)
        }
    })

  })

  observeEvent(input$button2, {

    withProgress(message = 'Run 2', detail = '', value = 0, {
        for (i in 1:15) {
            incProgress(1/15)
            Sys.sleep(0.25)
        }
    })

  })
}

shinyApp(ui = ui, server = server)
person Ash    schedule 10.03.2020
comment
Привет, @Ash, могу я спросить, как ShinyServer обрабатывает файлы загрузки для разных пользователей? Например, предположим, что мое приложение позволяет пользователю загружать некоторые сгенерированные данные на основе их входных данных. Файл записывается как .csv через downloadHandler, а имя файла устанавливается как data.csv. Затем, если два пользователя одновременно нажимают кнопку загрузки, получат ли они свой собственный файл данных или один из них перезапишет файл другого? Я узнал, что у каждого пользователя будет свой сеанс, но что касается записи файла, будет ли у них свой собственный путь? - person Yunzhao Xing; 09.11.2020
comment
Привет @YunzhaoXing. Это не будет проблемой. Shiny не будет смешивать данные между пользователями, независимо от того, есть ли более одного пользователя на рабочий процесс. Единственное исключение из этого правила - если вы намеренно делаете свои данные глобальными, то есть с помощью оператора ‹< -. - person Ash; 10.11.2020
comment
Привет @Ash, спасибо за объяснение. Я понимаю, что данные не будут смешиваться между пользователями, но меня немного смущает файл загрузки. В блестящем документе, описании параметра содержимого в downloadHandler, говорится ... файл с одним аргументом, который является путем (строкой) несуществующего временного файла, и записывает содержимое в этот путь к файлу .... Похоже, shiny сначала сохранит данные во временном файле на сервере, а затем позволит пользователю загрузить его. Поскольку все пользователи приложения будут иметь одно и то же имя загружаемого файла, возникнут ли конфликты? Будет ли у каждого пользователя новый путь? - person Yunzhao Xing; 11.11.2020
comment
Кстати, вот две ссылки на документы, на которые я ссылался: shiny.rstudio.com/reference/ блестящий / последний / downloadHandler.html; mastering-shiny.org/action-transfer.html - person Yunzhao Xing; 11.11.2020