raoyutian / PaddleOCRSharp

PaddleOCRSarp是一个基于百度飞桨PaddleOCR的C++代码修改并封装的.NET的OCR工具类库。包含文本识别、文本检测、表格识别功能。本项目针对小图识别不准的情况下做了优化,比飞桨原代码识别准确率有所提高。 包含总模型仅8.6M的超轻量级中文OCR,单模型支持中英文数字组合识别、竖排文本识别、长文本识别。同时支持多种文本检测。
Apache License 2.0
617 stars 100 forks source link

ToList() 导致的性能损失 #46

Closed feast107 closed 4 months ago

feast107 commented 4 months ago

PaddleOCREngine.cs 中有一行 https://github.com/raoyutian/PaddleOCRSharp/blob/5b47f1383285107e92c695557511cbfa4224561b/PaddleOCRSharp/PaddleOCREngine.cs#L233

这里对 IEnumerable 进行了 ToList() 展开然后使用[Index]取值,这是一个危险的行为。鉴于上下文,这里只进行了一次取下标的行为。 因此 IEnumerable.ElementAt(index) 毫无疑问更适合的选择。那么这两者到底有什么区别,

考虑以下代码:

var list = Enumerable.Range(0, 10).ToList(); //创建一列数 [0~9]
var eighthElementAt = list.Order().Select(Print).ElementAt(8); // 通过 ElementAt(index)
var eighthIndexOf   = list.Order().Select(Print).ToList()[8]; // 通过 ToList()[index]
return;
T Print<T>(T value){ //输出计算过程中经过的值
    Console.Write(value + ",");
    return value;
}

Print 在中途用于体现整个函数计算了多少次 执行之后 eighthElementAteighthIndexOf 的结果都是 8, 但是过程完全不一样 这是执行之后的输出:

8,
0,1,2,3,4,5,6,7,8,9,

可见 ElementAt 会忽略中间不必要的计算,直接取到所需下标的值 但是 ToList 会强制对整个表达式计算成 List 对象,再进行取下标的操作,这无疑多出许多不必要的遍历。 一旦枚举数量上升,两者的性能差距会变得更明显

稍后我会提一个pr修复这个问题。