【发布时间】:2019-10-14 17:57:02
【问题描述】:
我们需要在大约 300 万个单元格的大型工作簿中查找公式错误。性能至关重要。我们已经围绕特殊单元实现了一个包装函数,它允许我们在该工作表上没有找到错误单元的情况下捕获异常。类似于:
Handling "No cells were found." Error in Excel
但问题是,当抛出 COM 异常时,检查变得非常缓慢。更具体地说,当工作表上出现一个错误时,我们记录的执行时间在 1 到 4 毫秒之间。当错误被抛出时,我们正在查看大约 80 毫秒。
有没有人有任何创造性的快速替代方法来检查不存在的错误?
我们的代码:
try
{
dynamic cellsWithErrors = cells.SpecialCells(cellType, valueType);
return cellsWithErrors;
}
catch (COMException)
{
return null;
}
注意事项:
发现存在的错误很好,因此无需关注这一点。
我已经发现使用动态类型而不是 Range 类型可以适度加速
我们的检查会遍历整个工作簿中的所有工作表。因此,我们也很乐意看到任何适用于工作簿的解决方案,但怀疑它是否存在。
我们将其编写为 VSTO 插件的一部分并使用互操作层。
已经考虑的解决方案
我们可以将整个范围读取为值并对其进行迭代,但希望看看是否还有其他内容。因为在出现错误的情况下,这会变慢。
当前想法
所以难题归结为这一点。一方面,SpecialCells 在找到结果时非常快。但是抛出异常会导致 20 到 80 倍的减速。另一方面,读取纸张的整个使用范围在性能方面非常一致:我会说它与单元格的数量成线性关系,并且一次性支付少量的固定首付。现在,通过检查单元格值,可能会发现错误,在这里使用 Mike Rosenblum 的答案:How to know if a cell has an error in the formula in C#。如果是这样,那么我们将有另一种方法来检查错误。
然后的想法是编写一个主函数,该函数以相关工作表的大小为中心。如果它是一个非常大的工作表(我认为我们有一个大约有 200 万个单元格的工作表),那么我们不妨只使用 SpecialCells 并接受发生异常的成本。但是对于较小的工作表,异常的成本超过了在整个范围内读取并在内存中遍历它的成本,那么我们应该只做后者。
对于这种方法,我们需要确定的关键是交叉点是什么:SpecialCells 从哪里开始优于读取和迭代?我们可能还想利用我们自己对工作簿的了解来启发式地猜测哪些工作表可能有错误,哪些没有。如果我们开发一个并且我有时间,我会发布一个答案。
【问题讨论】:
标签: c# performance excel-interop