简体   繁体   English

如何在 R HTTPUV startServer 中实现异步调用?

[英]How to implement async calls in R HTTPUV startServer?

The R httpuv startServer function should support async processing in the call portion of the app parameter but I'm not able to get it to work. R httpuv startServer function 应该在 app 参数的调用部分支持异步处理,但我无法让它工作。 Does anyone know how to do this?有谁知道如何做到这一点? The example below won't work but it shows the idea of what I'm trying to do, run each request (or for a specific page) async so a page can load while another request is processing.下面的示例不起作用,但它显示了我正在尝试执行的操作,异步运行每个请求(或特定页面),以便在另一个请求正在处理时加载页面。

startServer(
        host,
        port,
        app = list(
          call = function(req) {
            req <- list(
              "REQUEST_METHOD" = req$REQUEST_METHOD,
              "SCRIPT_NAME" = req$SCRIPT_NAME,
              "PATH_INFO" = req$PATH_INFO,
              "QUERY_STRING" = req$QUERY_STRING,
              "SERVER_NAME" = req$SERVER_NAME,
              "SERVER_PORT" = req$SERVER_PORT,
              "HEADERS" = req$HEADERS,
              "rook.input" = req[["rook.input"]]$read_lines()
            )

            future_promise({
              if(req$PATH_INFO %in% valid_dynamic_paths){

                x <- eval(dynamic[[req$PATH_INFO]][req$REQUEST_METHOD])

                list(
                  status = x[["status"]],
                  headers = x[["headers"]],
                  body = x[["body"]]
                )

              }else{

                list(
                  status = 404,
                  headers = list(
                    'Content-Type' = 'text/html'
                  ),
                  body = "404. Page not found."
                )

              }
            })
          },
          staticPaths = static
        )
      )

I was able to get something similar to work.我能够得到类似于工作的东西。 The code below shows the gist of it:下面的代码显示了它的要点:

# fork a process for each new request
future::plan(future::multicore)

httpuv::runServer("0.0.0.0", 8080, list(
    call = function(req) {
        # `as.promise` is necessary, because `httpuv` is using `is.promise`
        # under the hood to act differently. Unfortunately `is.promise` returns
        # `FALSE` for a `future`.
        promises::as.promise(
            future::future({
                Sys.sleep(5)

                # Respond with HTTP 200 OK
                list(
                    status = 200,
                    body = "Slept for 5 seconds",
                    headers = list(
                        # Content-Type is important, otherwise you will run
                        # into a "not compatible with STRSXP" error.
                        "content-type" = "text/plain"
                    )
                )
            })
        )
    }
))

Calling the server with to requests at (nearly) the same time, will show that you are waiting only for 5 seconds for both requests, and not 5 for one and 10 for the other.在(几乎)同时调用服务器请求,将表明您只等待两个请求的 5 秒,而不是一个等待 5 秒,另一个等待 10 秒。

time curl -s localhost:8080 > /dev/null &
time curl -s localhost:8080 > /dev/null 

# After 5 seconds you should see output similar to the following:

# real    0m5.089s
# user    0m0.011s
# sys     0m0.010s

# real    0m5.112s
# user    0m0.020s
# sys     0m0.024s

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM