Java 7 ForkJoinPool和 Java 8 的并行Stream有助于并行化东西,这在您将 Java 程序部署到多核处理器机器上时非常有用。与跨网络上的不同机器进行扩展相比,这种并行性的优势在于您几乎可以完全消除延迟效应,因为所有内核都可以访问相同的内存。但是不要被并行的效果所迷惑!记住以下两点:
-
并行性会吞噬你的核心。这对于批处理非常有用,但对于异步服务器(例如 HTTP)来说则是一场噩梦。在过去的几十年里,我们使用单线程 servlet 模型是有充分理由的。因此,并行性仅在扩大规模时才有帮助。
-
并行性对算法的Big O Notation没有影响。如果您的算法是O(n log n),并且您让该算法在c内核上运行,您仍然会有一个O(n log n / c)算法,因为c在您的算法复杂性中是一个微不足道的常数。您将节省挂钟时间,但不会降低复杂性!
当然,提高性能的最佳方法是降低算法复杂度。杀手是实现O(1)或准O(1),当然,例如HashMap查找。但这并不总是可能的,更不用说容易了。如果你不能降低复杂性,如果你在真正重要的地方调整你的算法,如果你能找到正确的位置,你仍然可以获得很多性能。假设以下算法的可视化表示:
算法的整体复杂度是,或者如果我们要处理单个数量级。但是,在分析此代码时,您可能会发现一个有趣的场景:O(N3)O(N x O x P)
-
在您的开发框中,左分支 ( N -> M -> Heavy operation) 是您可以在分析器中看到的唯一分支,因为 和 的值O在P您的开发示例数据中很小。
-
然而,在生产中,正确的分支(N -> O -> P -> Easy operation或NOPE)确实造成了麻烦。您的运营团队可能已经使用AppDynamics或DynaTrace或一些类似软件解决了这个问题。
如果没有生产数据,您可能会很快得出结论并优化“繁重操作”。你运送到生产环境,你的修复没有效果。除了以下事实之外,没有优化的黄金法则:
-
设计良好的应用程序更容易优化
-
过早的优化不会解决任何性能问题,反而会使您的应用程序设计得不那么好,从而使优化变得更加困难
理论够了。让我们假设您找到了正确的分支是问题所在。很可能是一个非常简单的操作在生产中失败了,因为它被调用了很多次(如果N、O和P很大)。请在不可避免算法的叶节点出现问题的情况下阅读本文。这些优化不会帮助您扩展。他们将帮助您暂时节省客户的时间,将整体算法的困难改进推迟到以后!O(N3) 以下是 Java 中最简单的 10 个性能优化:
1、使用StringBuilder
这应该是几乎所有 Java 代码中的默认设置。尽量避免使用+操作符。当然,您可能会争辩说,它只是StringBuilder的语法糖,例如:
String x = "a" + args.length + "b";
复制代码
翻译为:
new java.lang.StringBuilder [16]dupldc <String "a"> [18]invokespecial java.lang.StringBuilder(java.lang.String) [20]aload_0 [args]arraylengthinvokevirtual java.lang.StringBuilder.append(int) : java.lang.StringBuilder [23]ldc <String "b"> [27]invokevirtual java.lang.StringBuilder.append(java.lang.String) : java.lang.StringBuilder [29]invokevirtual java.lang.StringBuilder.toString() : java.lang.String [32]astore_1 [x]
复制代码
但是,如果稍后您需要使用可选部分修改您的字符串,会发生什么?
String x = "a" + args.length + "b"; if (args.length == 1) x = x + args[0];
复制代码
您现在将有第二个StringBuil