在插入许多不同的图像时,AddPictureFromBytes 会变成 O(n²) - 在 countDrawings/addMedia/countMedia/relsReader/addRels 中出现了反复的"通过全面扫描重新计算"模式
** 说明**
将 N * 歧义 * 图像通过 “ Addture FromBytes ” 插入到单个工作表中, 其环比大致为 O( n2 ), 而不是 O(n) 。 此调用路径上( 至少) 有四个不同的地方, 进行线性 “ sync. Map. Rang () ” 扫描, 并随 n 增长, 每一次调用 :
Drawings() ' -- -- 在Addicture FromBytes' (DrawingID:= f.countDrawings() + 1')的顶端无条件使用,以计算候选人DrawingID',但当工作表已经绘出一幅图(`ws')时,该数值就被丢弃,从现有关系中重新计算。 绘制!= " 预画() " 内的零分行,即在特定工作单上第一张照片之后的每次通话。 在v2.9.1至v2.11.0(最晚)中确认为存在,不变。addMedia()'重复图像检查(f.Pkg.Rang'+`字节')。 与每个存储的媒体对等——对此采取散列指数化的方法(在#359中注意到),结果可以很好地解决大宗插入的个案。- 从
addMedia ()'调取的Media ()'伯爵,重新扫描所有`f'。 Pkg ' 只是为了计算下一个数字媒体文件名。 relsReader(drawingRels)'在AdPicture FromBytes'本身内进行关系-dedup扫描。
** 要复制的种子** 开始 主软件包
导入( E) "fmt" (英语). "GitHub.com/xuri/excelize/v2" (中文(简体) ). (中文(简体) ).
func 主 () { f: = 卓越. NewFile( ) 对于i:=0;i < 25000;i++ { img : = 使 DistinctPNGBytes( 一) / 任何有效的 PNG, 每i 必须不同 。 单元格 := fmt.Sprintf ("A%d", i+1) f.SetRowHeight ("Sheet1"), i+1, 160) (中文(简体) ). =f.Addture FromBytes ("Sheet1"),单元格,并excelize. 图片{ 扩展:".png",文件:img, 格式( excelize). Graphic Options{ AutoFit: true, CalmX: 0.98, CalmY: 0.98}, ) (中文(简体) ). {\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}你觉得呢? =f.saveAs ("out.xlsx") (中文(简体) ). {\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}你觉得呢?
** 观察到的结果**(n=25 000,苹果M系列,只嵌入回路——不包括图像生成):
时间 时间
|-|-|-.
==============================================================================================================================================================================
+ 修补 rels Reader 扫描, 添加Media dedup 扫描, 计数Media 扫描 + ~ 24.3s + QQ
+ 额外省略冗余的 " Drawings() " 调用 ~8.3s (~4.7–4.9x 总计) ~
被调用时间也证实了无标本版本的超线性增长——如调用 #1 → 26μs vs调用 #25,000 → 2.7ms (~100x),与每调用 O(n) 成本一致而非O(1).
** 预期结果**:接近线性总缩放;每个`从Bytes到AdPicture ' 的调用不需要重新扫描,与已经存在的图片/媒体/绘图数量成正比。
** Fix**:我有一个本地补丁(媒体解码的hash-bucket索引、一个原子计数器取代了“CounterMedia()”扫描、一个索引化的检索取代了关系解码扫描、以及当工作表已有了图纸时跳过“countDrawings()”调用),生成了上面的~8.3的结果,并核实正确性(第一/最后图像的字节一致圆通路,不同图像之间没有去掉的假阳性)。 如果有用,很高兴打开公关
** `addrels()`**'中的第五起相关案例
在描述补丁版本时,`addRels()' (excelize.go)成为了新的主导成本——它在每个呼叫中进行全面扫描,以计算下一个未使用的版本
. . . . . . .内容来源: qax-os/excelize