通过网络读取和解析大型文本文件的最佳方式是啥?

Posted

技术标签:

【中文标题】通过网络读取和解析大型文本文件的最佳方式是啥?【英文标题】:What's the best way to read and parse a large text file over the network?通过网络读取和解析大型文本文件的最佳方式是什么? 【发布时间】:2010-09-13 07:35:12 【问题描述】:

我有一个问题,需要我从远程机器解析多个日志文件。 有几个并发症: 1) 文件可能正在使用中 2)文件可能非常大(100mb+) 3) 每个条目可能是多行的

为了解决使用中的问题,我需要先复制它。我目前正在将它直接从远程机器复制到本地机器,并在那里解析它。这导致了问题 2。由于文件很大,因此在本地复制它可能需要很长时间。

为了增加解析时间,我想让解析器多线程,但这使得处理多行条目有点棘手。

两个主要问题是: 1)我如何加快文件传输(压缩?,是否需要在本地传输?,我可以通过其他方式读取正在使用的文件吗?) 2) 在线程间拆分行时如何处理多行条目?

更新:我没有对服务器进行明显解析的原因是我希望对 CPU 的影响尽可能小。我不想影响系统即时测试的性能。

【问题讨论】:

【参考方案1】:

如果您正在读取一个顺序文件,您希望通过网络逐行读取它。您需要一种能够流式传输的传输方法。您需要检查您的 IO 流技术来解决这个问题。

像这样的大型 IO 操作不会从多线程中获得太多好处,因为您可以尽可能快地处理项目,因为您可以通过网络读取它们。

另一个不错的选择是将日志解析器放在服务器上,然后下载结果。

【讨论】:

如果直接通过网络复制一个 100mb 的文本文件需要 x 秒,而让远程客户端压缩并发送文件然后放气/读取需要 x/4 秒,这不值得吗? (注意,我实际上不知道压缩/发送/解压缩/读取需要多长时间) 无论如何你可以(并且应该)在网络上使用一些压缩。就像我说的,检查你的 IO 流选项——有些人建议了一些 zip 库。 OTOH,如果您可以将程序放在远程端,请在那里进行处理!【参考方案2】:

从性能的角度来看,更好的选择是在远程服务器上执行解析。除了特殊情况外,您的网络速度始终是瓶颈,因此限制您通过网络发送的数据量将大大提高性能。

这是许多数据库使用在服务器端运行的存储过程的原因之一。

通过使用多线程来提高解析速度(如果有的话)将被网络传输的相对速度所淹没。

如果您致力于在解析文件之前传输文件,您可以考虑的一个选项是在进行文件传输时使用动态压缩。 例如,有可用的 sftp 服务器可以即时执行压缩。 在本地,你可以使用libcurl之类的东西来做客户端的传输,它也支持动态解压。

【讨论】:

【参考方案3】:

考虑到您已经在复制文件,最简单的方法是在复制之前对其进行压缩,并在复制完成后解压缩。压缩文本文件将获得巨大收益,因为 zip 算法通常在它们上工作得很好。此外,您现有的解析逻辑可以保持不变,而不必将其连接到远程网络文本阅读器。

这种方法的缺点是不能非常有效地逐行更新,这对于日志解析器来说是一件好事。

【讨论】:

我很想压缩它,但是如果我的代码在本地机器上运行,它会在传输后被压缩,这与目的不符。我想我最终不得不编写一个除了压缩和发送之外什么都不做的客户端。【参考方案4】:

我想这取决于它有多“远程”。 100Mb LAN 上的 100MB 大约需要 8 秒……达到千兆位,大约 1 秒就可以了。卡 50 * 2 美元,交换机 100 美元将是您可以进行的非常便宜的升级。

但是,假设它比这更远,您应该能够以只读模式打开它(当您复制它时正在阅读它)。 SMB/CIFS 支持文件块读取,因此您应该在此时流式传输文件(当然,您实际上并没有说明您是如何访问文件的 - 我只是假设 SMB)。

多线程无济于事,因为无论如何你都会受到磁盘或网络的限制。

【讨论】:

【参考方案5】:

使用压缩进行传输。

如果您的解析确实拖慢了您的速度,并且您有多个处理器,您可以分解解析工作,您只需要以一种聪明的方式来完成它 - 有一个确定性算法,由工作人员负责处理不完整的记录。假设您可以确定一行是记录中间的一部分,例如,您可以将文件分成 N/M 段,每个段负责 M 行;当其中一个作业确定其记录未完成时,它只需要继续阅读,直到到达记录的末尾。当其中一个作业确定它正在读取它没有开始的记录时,它应该跳过该记录。

【讨论】:

【参考方案6】:

如果你可以复制文件,你就可以阅读它。所以一开始就没有必要复制它。

编辑:使用FileStream class 可以更好地控制访问和共享模式。

new FileStream("logfile", FileMode.Open, FileAccess.Read, FileShare.ReadWrite)

应该可以解决问题。

【讨论】:

我不同意。根据我的经验,当尝试在流中解析它时,复制一个正在使用的将不会起作用。我的理论是,copy 使用了其他一些允许它的 windows api。 你的理论是错误的,恕我直言。 Windows Explorer 使用与 .NET(和 FileStream)相同的 API。你试过了吗?【参考方案7】:

我使用SharpZipLib 压缩大文件,然后再通过 Internet 传输它们。所以这是一种选择。

1) 的另一个想法是创建一个在远程机器上运行并在那里进行解析的程序集。您可以使用 .NET 远程处理从本地计算机访问程序集。远程程序集需要是 Windows 服务或托管在 IIS 中。这将允许您将日志文件的副本保存在同一台机器上,理论上处理它们需要更少的时间。

【讨论】:

【参考方案8】:

我认为使用压缩 (deflate/gzip) 会有所帮助

【讨论】:

【参考方案9】:

给定的答案不能让我满意,也许我的答案会帮助其他人不要认为它是超级复杂的,或者多线程在这种情况下不会受益。也许它不会使传输更快,但根据解析的复杂性,它可能会使解析数据的解析/或分析更快。

这真的取决于你的解析细节。您需要从日志文件中获取哪些信息?这些信息是像统计信息还是依赖于多个日志消息? 您有多种选择:

我想同时解析多个文件是最简单的,你将文件作为上下文,并且可以为每个文件创建一个线程 前面提到的另一个选项是对网络通信使用压缩 您还可以使用帮助程序,将日志文件拆分为属于一起的行作为第一步,然后使用多个线程处理这些行块;这个依赖行的解析应该非常容易和快速。

在这种情况下,衡量您的实际瓶颈是什么非常重要。如果您的瓶颈是网络,您将不会从优化解析器中受益。如果您的解析器创建了许多相同类型的对象,您可以使用 ObjectPool 模式并创建具有多个线程的对象。尝试在不分配太多新字符串的情况下处理输入。解析器通常是通过使用大量的 string.Split 等来编写的,这并不像它可能的那么快。您可以通过检查即将到来的值来导航 Stream,而无需读取完整的字符串并再次拆分它,而是在解析完成后直接填充您需要的对象。

优化几乎总是可能的,问题是你有多少投入,你的场景有多重要。

【讨论】:

以上是关于通过网络读取和解析大型文本文件的最佳方式是啥?的主要内容,如果未能解决你的问题,请参考以下文章

为 UWP 应用加载不同语言的不同文本文件的最佳方式是啥?

从 Perl 中的文本文件读取时跳过标题的最佳方法是啥?

在 asp.net-mvc 中从服务器读取文本文件的最佳方法是啥

在 Powershell 中,按记录类型拆分大型文本文件的最有效方法是啥?

从 pdf 文件导入/读取数据的最佳方法是啥?

从应用程序中存储的文本文件中读取数据的最佳方式