【问题标题】:Reading from NetworkStream. Which is better ReadLine() vs. Read into ByteArray?从 NetworkStream 读取。 ReadLine() 与读入 ByteArray 哪个更好?
【发布时间】:2011-05-19 12:26:15
【问题描述】:

我正在使用 TcpClient 与以“\n”分隔的字符串形式发送信息的服务器进行通信。数据流非常高,一旦设置了通道,流将始终具有要读取的信息。消息的大小可以变化。

我现在的问题是,最好使用 ReadLine() 方法从流中读取消息,因为它们已经“\n”分隔,还是建议读取一些固定大小的 byteArray 并获取使用 Split("\n") 之类的消息字符串? (是的,我确实理解字节数组可能只获取消息的一部分的情况,我们也必须为此实现逻辑。)

这里需要考虑的点是:

  • 性能。

  • 数据丢失。如果客户端的读取速度不如数据传入的速度快,是否会丢失一些数据?

  • 多线程设置。如果此设置必须在多线程环境中实现,其中每个线程将有一个单独的通信通道,但会在客户端上共享相同的资源。

【问题讨论】:

    标签: c# .net multithreading stream


    【解决方案1】:

    如果性能是您主要关心的问题,那么我更喜欢 Read 而不是 ReadLine 方法。 I/O 是程序可以执行的较慢的事情之一,因此您希望通过预先读取尽可能多的数据来最大限度地减少 I/O 例程中的时间。

    如果您使用 TCP,数据丢失在这里并不是一个真正的问题。 TCP 协议保证传送并将处理导致丢包的拥塞问题。

    对于问题的线程部分,我们需要更多信息。共享什么资源,是否共享TcpClient's 等...

    【讨论】:

    • 感谢您的帮助。是的,性能是一个主要问题,但你认为读入 byteArray、转换为字符串、检查部分消息和拆分消息不会是额外的开销并且仍然会表现得更好吗?
    • 对于共享资源,关心的基本上是客户端机器上的内存空间。
    • @Danish,一点字符串操作几乎肯定比多次 IO 调用要快。
    【解决方案2】:

    如果您需要大量性能,我会说使用缓冲区池并手动读取(在套接字上的 Read())。缓冲缓冲区可以避免产生垃圾,因为我相信 ReadLine() 会产生一些。

    由于您使用的是 TCP,因此数据丢失应该不是问题。

    在多线程设置中,您必须具体,但一般来说,资源共享很麻烦,因为它可能会产生数据竞争。

    【讨论】:

    • 感谢您的建议,但是我不太清楚您如何推荐使用缓冲池,您能否详细说明一下,示例代码 sn-p 会很棒。 . 再次感谢。
    【解决方案3】:

    为什么不使用BufferedStream 来确保您从流中以最佳方式阅读:

    var req = (HttpWebRequest)WebRequest.Create("http://www.stackoverflow.com");
    using(var resp = (HttpWebResponse)req.GetResponse())
    using(var stream = resp.GetResponseStream())
    using(var bufferedStream = new BufferedStream(stream))
    using(var streamReader = new StreamReader(bufferedStream))
    {
        while(!streamReader.EndOfStream)
        {
            string currentLine = streamReader.ReadLine();
            Console.WriteLine(currentLine);
        }
    }
    

    当然,如果您想要扩展,那么异步将是必要的。因此,ReadLine 是不可能的,您将回到字节数组操作。

    【讨论】:

    • 我认为使用 BufferedStream 不适合我的要求。正如我之前提到的,网络流将有大量传入数据包,除非客户端发送终止请求,否则它不会终止。使用 BufferedStream 意味着无限阻塞以首先将所有传入数据读入其中,这在此处是不可行的。
    • 据我了解, BufferedStream 只是确保读取传入数据以缓冲区大小的块而不是以您请求它的速率发生。例如,如果您从流中读取的数据大小小于流的缓冲区大小,那么您的读取效率很低。缓冲流通过将读取与缓冲区大小对齐来解决此问题。因此,它所保存的数据永远不会超过缓冲区的价值,但会使您的读取更有效率。它不会缓冲整个流。
    • 好吧,即使我也有类似的想法,但是当我尝试通过设置缓冲区大小来实现它时,它导致了一个错误“流不支持搜索”。如果我没有设置缓冲区大小,它会无限期地等待。
    【解决方案4】:

    我会读入一个字节数组......唯一的缺点:有限的大小。您需要知道一定的字节数量限制,或者有时手动将字节数组刷新为字节集合,然后将集合转换回字节数组,还使用 ​​bitConverter 将其转换为字符串,最后将其拆分为真实信息:p

    将数组刷新到集合中会产生很多开销...但是,刷新到字符串中需要更多资源,因为当您将字节刷新到字符串中时,必须对其进行解码......所以它已经完成了对你来说......你可以选择字符串的简单性或字节的效率,无论哪种方式,它都不会完全相互提升性能,但我个人会使用字节集合来避免隐式字节转换。

    重要提示:这来自以前使用 TCP 套接字的个人经验(Quake RCON 的东西),而不是任何书或任何东西 :) 如果我弄错了,请纠正我。

    【讨论】:

    • 我想,我会读取一个 2048 大小的字节数组,将其转换为字符串,然后将其拆分为单独的消息字符串。恕我直言,使用字节集合会增加更多复杂性而不会带来太多收益。谢谢您的帮助。
    猜你喜欢
    • 1970-01-01
    • 2017-06-24
    • 1970-01-01
    • 2017-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-04
    • 2017-11-21
    相关资源
    最近更新 更多