【问题标题】:How to Increase the Performance of Unit Tests that Need to Load Very Large File如何提高需要加载超大文件的单元测试的性能
【发布时间】:2016-01-23 22:03:58
【问题描述】:

我有一个使用Stanford's CoreNLP 包的Java NLP 项目。我有几个项目的单元测试,我喜欢经常运行它们,以了解细微的调整如何影响系统的输出。不幸的是,CoreNLP 包需要加载a model of the English language 才能执行其分类和标记,而且这个文件太大,需要几秒钟才能加载到内存中。这似乎没有太多的等待时间,但单元测试本身需要几毫秒才能运行,而且每次我开始新的测试运行时,我都必须等待模型文件加载,这似乎是一种耻辱。

有没有办法让模型文件加载一次,然后针对已经在内存中的模型运行后续单元测试?也许类似于存储模型并可以从单元测试中调用的测试“服务器”?我以前从未处理过这样的事情,所以我真的不知道从哪里开始。

【问题讨论】:

  • 在静态方法before your suite中加载一次模型。
  • 我确实以静态方法加载了一次模型。抱歉,如果我不清楚:我想在每次计算机启动时加载一次模型。本质上,只有第一个套件运行会很慢,所有其他套件运行应该很快。那有意义吗?我不知道如何最好地表达它。
  • 要在运行之间重用数据,您需要将其加载到可以在共享内存中使用的表单中。例如内存映射文件。不确定是否值得。如果它为您的整个单元测试运行增加了几秒钟,则可能无法更改。
  • 首先要做的是检查基础知识:用于加载文件的代码是什么?你有 SSD 吗?
  • 我实际上已经使用 Java RMI 编写了一个可行的解决方案。服务器加载文件并坐在那里等待来自单元测试的调用。不过不确定这是否理想。

标签: java performance unit-testing junit


【解决方案1】:

在单元测试中,这种情况的典型解决方案是将您的代码与“令人不安”的库隔离(即消除依赖性)或使用双精度代码(如存根或模拟)。针对实际数据库的单元测试被认为是“测试气味”。

【讨论】:

  • 我认为这与其说是一种气味,不如说是根据定义将测试变成集成测试,而不是单元测试。这不是“坏”,这只是另一回事。不应该把它们混在一起
  • 完全同意。单元测试在这里不是正确的术语,它确实是一个集成测试。
【解决方案2】:

一般来说,如果您使用的是现代操作系统,例如 Linux,那么在短时间内对同一文件的后续读取将被 buffer cache 缓存 - 除非文件非常大或您缺少空闲内存。这不仅仅是理论上的 - 您可以轻松地运行 JUnit 测试,其中包含一些分析表明多次加载文件将导致除第一次加载之外的所有速度接近memcpy,只要文件大致适合可用 RAM。

也就是说,只要文件在缓存中,它通常会在现代台式机或服务器硬件上以 5 GB/s 或更快的速度加载。如果文件太大而无法保存在缓存中 - 那么许多其他解决方案已经被排除在外:因为将文件保存在共享内存中的守护程序等替代方案无论如何都需要相同数量的 RAM。

这都是关于读取文件的原始成本(例如,使用 Java 的 InputStream 或其他读取原始文件的类)。 “加载”文件的真正成本很可能在于您需要执行的特定于应用程序的解析,以将文件转换为预期的内存格式。在这种情况下,您当然可以考虑某种长寿命的缓存进程,该进程在 Java 调用中将文件保存在内存中。你可以使用现成的东西,比如 redis 或 memcached,但你必须确保你的反序列化方案比你的解析方案快得多。

最终,您需要分析库对有问题文件的负载。是 IO 受限(即大部分时间花在 IO 函数中阻塞),还是 CPU 受限(例如,大部分时间花在解析或其他函数上处理)?只有这样,您才能确定需要缓存到什么级别才能发挥作用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-05-08
    • 2015-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-18
    相关资源
    最近更新 更多