【问题标题】:Reading from a socket 1 byte a time vs reading in large chunk一次从套接字读取 1 个字节与读取大块
【发布时间】:2010-10-30 05:22:24
【问题描述】:

一次从套接字读取 1 个字节与从大块读取之间有什么区别 - 性能方面?

我有一个 C++ 应用程序,它需要从 Web 服务器中提取页面并逐行解析接收到的页面。目前,我一次读取 1 个字节,直到遇到 CRLF 或达到最大 1024 个字节。

如果读取大块(例如一次 1024 字节)在性能方面要好得多,任何关于如何实现我目前拥有的相同行为的想法(即能够一次存储和处理 1 个 html 行- 直到 CRLF 还没有消耗后续字节)?

编辑:

我负担不起太大的缓冲区。由于该应用程序用于嵌入式设备,因此我的代码预算非常紧张。我更喜欢只保留一个固定大小的缓冲区,最好一次保留一个 html 行。这使我的解析和其他处理变得容易,只要我尝试访问缓冲区进行解析,我可以假设我正在处理一个完整的 html 行。

谢谢。

【问题讨论】:

  • 您能否提供有关嵌入式设备的更多详细信息?它甚至有操作系统吗?

标签: c++ c sockets cgi


【解决方案1】:

我无法评论 C++,但来自其他平台 - 是的,这会产生巨大的不同;尤其是代码需要执行的切换数量,以及需要担心流的异步性质等的次数。

但真正的考验当然是对其进行剖析。为什么不编写一个使用这两种方法在任意文件中搅动的基本应用程序,并针对一些典型文件对其进行测试……效果通常令人吃惊,如果代码是 IO 绑定的。如果文件很小,并且您的应用程序运行时大部分时间都用于处理内存中的数据,那么您可能不会注意到任何差异。

【讨论】:

    【解决方案2】:

    如果您是直接从套接字读取,而不是从可以缓冲的中间高级表示中读取,那么毫无疑问,最好完全读取 1024 个字节,将它们放在 RAM 中的缓冲区中,然后解析RAM中的数据。

    为什么?在套接字上读取是一个系统调用,它会在每次读取时导致上下文切换,这很昂贵。阅读更多信息:IBM Tech Lib: Boost socket performances

    【讨论】:

    • +1 - 我喜欢你关于为什么大块阅读在性能方面更好的论点。我想我可以接受 Neil Butterworth 的回答来解决我的第二个问题。 =)
    【解决方案3】:

    第一个也是最简单的:

    cin.getline(buffer,1024);
    

    其次,通常所有的IO都是缓冲的,所以你不用太担心

    第三,CGI 进程启动通常比输入处理成本高得多(除非它是巨大的 文件)...所以你可能不会考虑它。

    【讨论】:

      【解决方案4】:

      生日,

      一次处理一个字节对性能的重大影响之一是,您的上下文会一遍又一遍地从用户时间进入系统时间。结束了。一点效率都没有。

      抓取一个大块,通常达到 MTU 大小,效率明显更高。

      为什么不将内容扫描到一个向量中并对其进行迭代,寻找 \n 以将您的输入分隔为 Web 输入行?

      HTH

      干杯,

      【讨论】:

      • 是的,根据调用次数的不同,函数调用引起的相对开销在某些时候实际上可能会变得很大。
      【解决方案5】:

      您不是一次从套接字读取一个字节,而是一次从 C/C++ I/O 系统读取一个字节,如果您使用 CGI,它已经缓冲了来自插座。缓冲 I/O 的全部意义在于让程序员可以方便地处理数据,因此如果您想一次处理一个字节,请继续。

      编辑:经过反思,您的问题并不清楚您是在实现 CGI 还是只是在使用它。您可以通过发布代码 sn-p 来澄清这一点,该代码指示您当前如何读取该单个字节。

      如果您直接读取套接字,那么您应该简单地将对 GET 的整个响应读取到缓冲区中,然后对其进行处理。这具有许多优点,包括性能和易于编码。

      如果您被限制在一个小缓冲区,那么请使用经典的缓冲算法,例如:

      getbyte:
         if buffer is empty
            fill buffer
            set buffer pointer to start of buffer
         end
         get byte at buffer pointer
         increment pointer
      

      【讨论】:

      • 不。我正在从套接字读取。我正在向 Web 服务器发出 HTTP GET 请求并从套接字读取响应。我这样做是因为我需要完全渲染和解析的动态内容。
      • 我想我可以稍微修改一下这个算法。我可以有两个固定大小的缓冲区。一个读取整个文件(比如 512 个字节),扫描它并将一个完整的 html 行存储在另一个缓冲区中,我可以在其他解析方法中轻松访问该缓冲区。我可以有一个更有效的套接字读取例程,并且我可以保持我现在拥有的易于处理(即我的其他方法假设一个完整的 html 行)。谢谢。 =)
      【解决方案6】:

      您可以使用 fdopen() 函数打开套接字文件描述符。然后你有缓冲的 IO,所以你可以在那个描述符上调用 fgets() 或类似的。

      【讨论】:

        【解决方案7】:

        在操作系统级别没有区别,数据无论如何都会被缓冲。但是,您的应用程序必须执行更多代码才能一次“读取”一个字节。

        【讨论】:

          猜你喜欢
          • 2016-09-24
          • 2023-03-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-10-20
          • 2015-09-01
          • 2015-05-08
          相关资源
          最近更新 更多