我们做对了,现在是时候更快地做事了。 我们会牢记Donald Knuth的警告:“大约97%的时间,我们应该忘记效率低下:过早的优化是万恶之源”。

根据Jonathan Hedley的介绍,他使用YourKit Java Profiler来测量内存使用情况并找到性能热点。 使用此类工具的统计结果对于优化的成功至关重要,它将阻止您花费时间思考和进行无用的调优,这不会提高性能,但也会使代码不必要地变得复杂且难以维护。 乔纳森(Jonathan)在“科隆(Colophon)”中也谈到了这一点。

我们将列出Jsoup中使用的一些技巧和窍门,它们目前是随机排序的,将来会重新组织。


1.缩进填充

// memoised padding up to 21, from "", " ", "  " to "                   "
static final String[] padding = {......};public static String padding(int width) {if (width < 0)throw new IllegalArgumentException("width must be > 0");if (width < padding.length)return padding[width];char[] out = new char[width];for (int i = 0; i < width; i++)out[i] = ' ';return String.valueOf(out);
}protected void indent(Appendable accum, int depth, Document.OutputSettings out) throws IOException {accum.append('\n').append(StringUtil.padding(depth * out.indentAmount()));
}

很聪明吧? 它保留了不同长度的填充缓存,可以覆盖80%的情况-我认为这是基于作者的经验和统计数据。

2.是否上课?

Element#hasClass被标记为对性能敏感的 ,例如,我们要检查<div class="logged-in env-production intent-mouse">是否具有类production ,将类按空格分割为一个数组,然后循环并进行搜索,但深入了解这将是无效的。 Jsoup首先在这里介绍了Early Exit ,方法是将长度与目标类名进行比较,以避免不必要的扫描和搜索,这也将是有益的。 然后,它使用一个检测空白的指针并执行regionMatches-坦白地说,这是我第一次了解方法String#regionMatches &#55357;&#56904;&#55357;&#56837;。

public boolean hasClass(String className) {final String classAttr = attributes().getIgnoreCase("class");final int len = classAttr.length();final int wantLen = className.length();if (len == 0 || len < wantLen) {return false;}// if both lengths are equal, only need compare the className with the attributeif (len == wantLen) {return className.equalsIgnoreCase(classAttr);}// otherwise, scan for whitespace and compare regions (with no string or arraylist allocations)boolean inClass = false;int start = 0;for (int i = 0; i < len; i++) {if (Character.isWhitespace(classAttr.charAt(i))) {if (inClass) {// white space ends a class name, compare it with the requested one, ignore caseif (i - start == wantLen && classAttr.regionMatches(true, start, className, 0, wantLen)) {return true;}inClass = false;}} else {if (!inClass) {// we're in a class name : keep the start of the substringinClass = true;start = i;}}}// check the last entryif (inClass && len - start == wantLen) {return classAttr.regionMatches(true, start, className, 0, wantLen);}return false;
}

3.标签名称是否存在?

正如我们在之前的文章中所分析的那样, HtmlTreeBuilderState将通过检查某个集合中的标记名称是否正确来验证嵌套的正确性。 我们可以比较1.7.3之前和之后的实现以进行检查。

// 1.7.2
} else if (StringUtil.in(name, "base", "basefont", "bgsound", "command", "link", "meta", "noframes", "script", "style", "title")) {return tb.process(t, InHead);
}// 1.7.3
static final String[] InBodyStartToHead = new String[]{"base", "basefont", "bgsound", "command", "link", "meta", "noframes", "script", "style", "title"};
...
} else if (StringUtil.inSorted(name, Constants.InBodyStartToHead)) {return tb.process(t, InHead);
}

根据作者的评论,“这里有点难读,但与动态varargs相比,GC更少。 贡献了大约10%的解析GC负载。 必须确保将这些排序,如在findSorted中使用的一样。 简单地使用static final常量数组,也可以对其进行排序,以便二进制搜索也可以从O(n)改进为O(log(n)),在这里性价比非常好。

但是,“如果添加更多的数组,则必须更新HtmlTreebuilderStateTest”不是同步恕我直言的好方法,而不是复制和粘贴,我将使用反射来检索这些常量。 您可以在Pull Request #1157中找到我的建议:“简化状态排序状态单元测试–避免在HtmlTreeBuilderStateTest.java中重复代码” 。

4.轻量级模式

您知道Integer.valueOf(i)的技巧吗? 如果已配置( java.lang.Integer.IntegerCache.high ),则它将维护从-128到127或更高的IntegerCache缓存,结果,当值位于不同范围时, == equals结果将有所不同(经典Java面试问题?)。 这实际上是一个轻量级模式的示例。 对于Jsoup,应用此模式还将减少对象创建的时间并提高性能。

/*** Caches short strings, as a flywheel pattern, to reduce GC load. Just for this doc, to prevent leaks.* <p />* Simplistic, and on hash collisions just falls back to creating a new string, vs a full HashMap with Entry list.* That saves both having to create objects as hash keys, and running through the entry list, at the expense of* some more duplicates.*/
private static String cacheString(final char[] charBuf, final String[] stringCache, final int start, final int count) {// limit (no cache):if (count > maxStringCacheLen)return new String(charBuf, start, count);if (count < 1)return "";// calculate hash:int hash = 0;int offset = start;for (int i = 0; i < count; i++) {hash = 31 * hash + charBuf[offset++];}// get from cachefinal int index = hash & stringCache.length - 1;String cached = stringCache[index];if (cached == null) { // miss, addcached = new String(charBuf, start, count);stringCache[index] = cached;} else { // hashcode hit, check equalityif (rangeEquals(charBuf, start, count, cached)) { // hitreturn cached;} else { // hashcode conflictcached = new String(charBuf, start, count);stringCache[index] = cached; // update the cache, as recently used strings are more likely to show up again}}return cached;
}

还有另一种情况,可以使用相同的想法来最小化新的StringBuilder GC。

private static final Stack<StringBuilder> builders = new Stack<>();/*** Maintains cached StringBuilders in a flyweight pattern, to minimize new StringBuilder GCs. The StringBuilder is* prevented from growing too large.* <p>* Care must be taken to release the builder once its work has been completed, with {@see #releaseBuilder}
*/
public static StringBuilder borrowBuilder() {synchronized (builders) {return builders.empty() ?new StringBuilder(MaxCachedBuilderSize) :builders.pop();}
}

实际上, CharacterReaderStringUtil值得越来越消化,因为有许多有用的提示和技巧会激发您的灵感。

5.其他改善方法

  • 使用RandomAccessFile读取文件,使文件读取时间缩短了2倍。 查看#248了解更多详情
  • 节点层次结构重构。 查看#911了解更多详细信息
  • “在很大程度上基于对各种网站的分析重新排序HtmlTreeBuilder方法而带来的改进” –我在此列出了这一点,因为它非常实用。 更深入地了解和观察代码的运行方式也将为您提供一些见解
  • 调用list.toArray(0)而不是list.toArray(list.size()) –已在某些开源项目(例如h2database)中使用 ,因此我也在另一个Pull Request #1158中提出了此要求

6.未知数

优化永无止境。 我目前还没有发现很多提示和技巧。 如果您能在Jsoup中找到更多启发性的想法,请与我分享,我将不胜感激。 您可以在本网站的左侧栏中找到我的联系信息,或者直接通过ny83427 at gmail.com发送电子邮件至ny83427 at gmail.com

-未完待续-

翻译自: https://www.javacodegeeks.com/2019/02/secrets-jsoup-tricks-optimization.html

Jsoup V的幕后秘密:优化的技巧和窍门相关推荐

  1. jsoup爬虫教程技巧_Jsoup V的幕后秘密:优化的技巧和窍门

    jsoup爬虫教程技巧 我们已经把事情做好了,现在是时候加快工作速度了. 我们会牢记Donald Knuth的警告:"大约97%的时间我们应该忘记效率低下:过早的优化是万恶之源". ...

  2. 淘宝搜索排名优化小技巧总结,不会的赶快来看看

    一.淘宝搜索优化的重要性: 淘宝搜索优化就是通过优化店铺的宝贝标题.类目.上下架时间等来获取相对较好的排名,从而获取淘宝搜索流量.淘宝搜索优化,是从本质上去迎合搜索引擎,当宝贝正确发布之后,由于宝贝或 ...

  3. php get 传循环出来的参数_PHP性能优化小技巧

    PHP性能优化小技巧: 1. foreach效率更高,尽量用foreach代替while和for循环. 2. 循环内部不要声明变量,尤其是对象这样的变量. 3. 在多重嵌套循环中,如有可能,应当将最长 ...

  4. 怎么做网络推广浅析有关404页面优化的技巧

    众所周知,怎么做网络推广表示,404页面是我们在打开浏览器时经常能看到的页面,也是很多网站因为一些有问题的页面或链接而建设的能提升用户体验,减少跳出率的一个页面.那么针对404页面有什么优化方法呢?下 ...

  5. OI常用的常数优化小技巧

    注意:本文所介绍的优化并不是算法上的优化,那个就非常复杂了,不同题目有不同的优化.笔者要说的只是一些实用的常数优化小技巧,很简单,虽然效果可能不那么明显,但在对时间复杂度要求十分苛刻的时候,这些小的优 ...

  6. mysql百万级去重_mysql优化小技巧之去除重复项(百万级数据)

    mysql优化小技巧之去除重复项(百万级数据) 发布时间:2018-06-11 11:54, 浏览次数:482 , 标签: mysql 说到这个去重,脑仁不禁得一疼,尤其是出具量比较大的时候.毕竟咱不 ...

  7. 新网站关键词优化小技巧

    网站已经基本成为每家企业的标配了,在网站搭建好后,只有经过SEO优化才能达到良好的推广效果.而新网站想要快速取得关键词排名也不是那么容易的,下面老齐SEO就给大家介绍几点关于新网站关键词优化的小技巧. ...

  8. linux机械硬盘提速,4个机械硬盘优化设置技巧 让你的硬盘速度飞起来

    原标题:4个机械硬盘优化设置技巧 让你的硬盘速度飞起来 虽然固态硬盘在速度上完胜机械硬盘,不过在容量.价格方面还是机械硬盘更有优势,在如今动辄十几个GB大小的游戏面前,SSD那点容量真心不够用.今天& ...

  9. nvme固态硬盘开机慢_6个固态硬盘优化设置技巧 让你的SSD速度飞起来 (全文)

    得益于强大的读写性能和低延迟特性,固态硬盘已经逐渐成为了新装机或买新电脑用户首选标配.不过,依然会有部分用户反馈,电脑明明有SSD,但还是出现了开关机速度慢.系统卡顿等现象.对于这种情况,其实相当一部 ...

最新文章

  1. 如何提升微服务的幸福感
  2. 为什么交叉熵和KL散度在作为损失函数时是近似相等的
  3. codevs1245 最小的N个和
  4. 消除UITableView下面的额外分隔符
  5. 如何判断一个点是否在一个多边形内?
  6. 阿里云ECS使用cloudfs4oss挂载OSS
  7. TypeScript里一些特殊的类型
  8. 华为杯数学建模优秀论文_数学建模经典例题(2016年国赛B题与优秀论文)
  9. distri.lua的web运维工具
  10. redis哨兵配置和redis-cluster搭建
  11. 工作后,成长速度是如何产生差异的?
  12. AutoJs学习-几个QQ群脚本(群引流\提取成员\加群友\加群)
  13. 相信美好就能遇见美好—西安独行三日短途穷游 攻略
  14. window上装python,pip
  15. 工作感悟_of_RS
  16. 【机器视觉运动控制一体机小课堂】三分钟对图像进行ROI创建
  17. 【AI】VGG网络简介
  18. “全包”给装修公司,验收时发现甲醛超标,能要求重装或赔偿吗?
  19. 用C#写PMAC的上位机,建立连接的步骤
  20. 计算机如何寻址硬盘,寻址

热门文章

  1. 【匈牙利算法】指引(jzoj 2319)
  2. Sentinel(十八)之注解支持
  3. 常用公有云接入——阿里
  4. json-lib的字符串自动转换坑
  5. Oracle入门(十二E)之视图操作
  6. 全球如何保证区块生成是匀速的?
  7. 树层级处理上万条数据优化!
  8. 自定义SpringBoot的运行动画---美女
  9. Android 获取屏幕宽度和高度直接转换为DP
  10. java的BASE64Encoder,BASE64Decoder加密与解密