【问题标题】:How can I stream multiple files at the same time using HTTP::Server?如何使用 HTTP::Server 同时流式传输多个文件?
【发布时间】:2017-06-28 12:43:00
【问题描述】:

我正在开发一个服务于大文件的 HTTP 服务。我注意到并行下载是不可能的。该过程一次只提供一个文件,所有其他下载都在等待之前的下载完成。如何同时流式传输多个文件?

    require "http/server"

    server = HTTP::Server.new(3000) do |context|
      context.response.content_type = "application/data"
      f = File.open "bigfile.bin", "r"
      IO.copy f, context.response.output
    end

    puts "Listening on http://127.0.0.1:3000"
    server.listen

一次请求一个文件:

    $ ab -n 10 -c 1 127.0.0.1:3000/

    [...]
    Percentage of the requests served within a certain time (ms)
     50%      9
     66%      9
     75%      9
     80%      9
     90%      9
     95%      9
     98%      9
     99%      9
    100%      9 (longest request)

一次请求 10 个文件:

    $ ab -n 10 -c 10 127.0.0.1:3000/

    [...]
    Percentage of the requests served within a certain time (ms)
     50%     52
     66%     57
     75%     64
     80%     69
     90%     73
     95%     73
     98%     73
     99%     73
    100%     73 (longest request)

【问题讨论】:

    标签: crystal-lang


    【解决方案1】:

    这里的问题是File#readcontext.response.output 都不会阻塞。 Crystal 的并发模型基于协作调度的 Fiber,其中切换 Fiber 仅在 IO 阻塞时发生。使用非阻塞 IO 从磁盘读取是不可能的,这意味着唯一可以阻塞的部分是写入context.response.output。但是,在同一台机器上,磁盘 IO 比网络 IO 慢很多,这意味着写入永远不会阻塞,因为 ab 的读取速度比磁盘提供数据的速度快得多,甚至从磁盘缓存中也是如此。这个例子实际上是打破水晶并发性的完美风暴。

    在现实世界中,服务的客户端更有可能驻留在机器的网络上,从而导致响应写入偶尔会阻塞。此外,如果您正在从另一个网络服务或管道/套接字读取数据,您也会阻塞。另一种解决方案是使用线程池来实现非阻塞文件 IO,这就是 libuv 所做的。作为旁注,Crystal 移至 libevent,因为 libuv 不允许多线程事件循环(即让任何线程恢复任何纤程)。

    调用Fiber.yield 将执行传递给任何待处理的纤程是正确的解决方案。下面是一个如何在读取文件时阻塞(和让步)的示例:

        def copy_in_chunks(input, output, chunk_size = 4096)
          size = 1
          while size > 0
            size = IO.copy(input, output, chunk_size)
            Fiber.yield
          end
        end
    
        File.open("bigfile.bin", "r") do |file|
          copy_in_chunks(file, context.response)
        end
    

    这是此处讨论的转录:https://github.com/crystal-lang/crystal/issues/4628

    给 GitHub 用户 @cschlack、@RX14 和 @ysbaddaden 的道具

    【讨论】:

      猜你喜欢
      • 2011-12-30
      • 2019-10-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-16
      • 1970-01-01
      • 2016-08-14
      • 2020-12-31
      相关资源
      最近更新 更多