遍历pocoUI树的效率

如何提高遍历pocoUI树的效率

工作中经常碰到需要遍历pocoUI树的情况。不同的写法差别很大,写个博客记录一下。
poco的实例,存储了整个项目的UI树,体积可能非常大。
以我手头的项目为例,其完整的UI树,以字典形式存在txt文本里,容量高达272k。遍历pocoUI树的效率
遍历pocoUI树的效率
poco树中的各种控件都有其属性,下面就以这个“UICarmeraRoot”对象为例进行各种写法的效率比对。遍历pocoUI树的效率
在对该poco实例进行操作前,先简单对其遍历一遍,看看耗时多少。遍历pocoUI树的效率
可知:遍历一个272k的字典,python只需要0.48秒。

1.offspring()
查询UI树里,最偷懒的写法就是直接生成一个全树的实例,然后取其所有后代,再在其后代中逐个查找符合条件的属性对应的对象。
示例代码为:

uioffspring=poco("UIRoot(Clone)").offspring()
for x in uioffspring:
	if x.attr("name") == 'UICameraRoot':
		print(x.get_text())
		print('查找控件过程结束')  
		break
	else :
		print("没找到")

然后这段代码执行所需时间为:144秒。
遍历pocoUI树的效率
分析一下,瓶颈应该出在if x.attr("name") == 'UICameraRoot':这句。
每次对poco实例的属性进行操作,都要重新生成一个dump,这非常耗费资源。遍历pocoUI树的效率
除非在之后的业务逻辑里要对offspring()进行不可同步的操作,否则不要采取这种方法。

2.offspring()指定参数
offspring方法里跟指定参数,可以将dump操作缩减为1次。大大提升效率。
示例代码如下:

ui_node_name = poco("UIRoot(Clone)").offspring(name='UICameraRoot')
print('查找控件XX结束')  

代码精简,效率也提升了几十倍。花费了4.8秒就从整个UI树中查询到了我们需要的控件。
遍历pocoUI树的效率
3.freeze
poco提供了freeze方法能再次加快查询效率。
遍历pocoUI树的效率
从freeze的源码可以看到,freeze()得到的是当前poco实例的一个静态副本。
我们可以通过下面的方式取到freeze实例。

freeze=poco.freeze()
hierarchy_dict = freeze.agent.hierarchy.dump()
print(hierarchy_dict)

尝试将之前的方法1和方法2,用到这个freeze实例上,
即将方法1里的
uioffspring=poco("UIRoot(Clone)").offspring()替换为
uioffspring=freeze("UIRoot(Clone)").offspring()
方法2 里的
ui_node_name = poco("UIRoot(Clone)").offspring(name='UICameraRoot')替换为
ui_node_name = freeze("UIRoot(Clone)").offspring(name='UICameraRoot')
看看结果会如何?
遍历pocoUI树的效率
遍历pocoUI树的效率
两种算法的耗时相差无几。且都低于对poco实例的操作耗时。
当然,freeze也不是没有缺点的,它是poco实例的静态对象,当poco发生变动时,不会实时更新。所以每次操作前,尽量重新冻结赋值;使用完最好也尽快释放,否则会占据大量的内存资源。

结论
除非需要操作整个UI树实例里的不同对象,否则尽量不要读取全树;读全树的效率比读单个控件的效率低2个数量级。
freeze的效率极高。但需要手动刷新。