Questions tagged «performance»

与提高应用程序性能有关的问题可能涉及从选择软件体系结构到算法选择的范围。


1
与每个循环的标准相比,Collection.stream()。filter()。forEach()效率低下吗?
IntelliJ IDEA刚刚向我建议用Java 8“ forEach”调用替换以下for-each循环: for (Object o : objects) { if (o instanceof SomeObject) { doSomething(); } } 推荐的电话如下所示: objects.stream().filter(o -> o instanceof SomeObject).forEach(o -> doSomething()); 除非我误解了Stream的基础功能如何工作,否则在我看来,使用stream是一个O(2n)操作,而不是标准for-each循环的O(n)操作。


4
SIMD编程代码库的维护成本
题: 软件行业的共识是,干净,简单的代码对于代码库和拥有它的组织的长期生存至关重要。这些属性导致较低的维护成本,并增加了继续使用代码库的可能性。 但是,SIMD代码与通用应用程序代码不同,我想知道是否有专门针对SIMD代码的简洁代码的相似共识。 我的问题的背景。 我为各种图像处理和分析任务编写了大量的SIMD(单指令,多个数据)代码。最近,我还不得不将少量这些功能从一种体系结构(SSE2)移植到另一种体系结构(ARM NEON)。 该代码是为收缩包装的软件编写的,因此,如果没有不受限制的重新分配权限(例如MATLAB),就不能依赖专有语言。 典型代码结构的示例: 使用OpenCV的矩阵类型(Mat)进行所有内存,缓冲区和生命周期管理。 检查输入参数的大小(尺寸)后,将获得指向每行像素起始地址的指针。 像素计数和来自每个输入矩阵的每一行像素的起始地址都传递给一些低级C ++函数。 这些低级C ++函数使用SIMD内部函数(用于Intel Architecture和ARM NEON),从原始指针地址加载并保存到原始指针地址。 这些低级C ++函数的特征: 唯一一维的(在内存中连续) 不处理内存分配。(每个分配,包括临时性,都由外部代码使用OpenCV工具处理。) 符号的名称长度(内部名称,变量名称等)的范围大约为10-20个字符,这是非常大的。(读起来就像是技术泡沫)。 不鼓励重复使用SIMD变量,因为编译器在正确地解析不是以“单分配”编码方式编写的代码方面存在很多缺陷。(我已经提交了几个编译器错误报告。) SIMD编程的哪些方面会使讨论与一般情况有所不同?或者,为什么SIMD与众不同? 初期开发费用 众所周知,与随便编写的 C ++代码相比,具有良好性能的C ++ SIMD代码的初始开发成本约为10倍至100倍(具有较大的余量)。 正如在性能与可读/清洁代码之间进行选择的答案中所指出的那样?,大多数代码(包括随便编写的代码和SIMD代码)起初既不干净也不快速。 不鼓励对代码性能(在标量代码和SIMD代码中)进行进化改进(因为这被视为一种软件返工),并且没有跟踪成本和收益。 就倾向而言 (例如帕累托原则,又称80-20规则) 即使图像处理仅占软件系统的20%(在代码大小和功能上),图像处理也相对较慢(当以所花费的CPU时间的百分比表示),花费的时间超过80%。 这是由于数据大小的影响:典型的图像大小以兆字节为单位,而非图像数据的典型大小以千字节为单位。 在图像处理代码中,SIMD程序员受过训练,可以通过识别C ++代码中的循环结构来自动识别包含热点的20%代码。因此,从SIMD程序员的角度来看,“重要的代码” 100%是性能瓶颈。 通常在图像处理系统中,存在多个热点,并占用相当比例的时间。例如,可能有5个热点分别占总时间(20%,18%,16%,14%,12%)。为了获得高性能,需要在SIMD中重写所有热点。 这被概括为气球弹出规则:气球不能两次弹出。 假设有一些气球,说5个。抽取它们的唯一方法是将它们逐个弹出。 弹出第一个气球后,剩下的4个气球现在占总执行时间的更高百分比。 为了获得更大的收益,然后必须弹出另一个气球。(这违背了80-20的优化规则:采摘了悬挂率最低的20%的水果后,可以获得良好的经济效果。) 在可读性和维护方面 SIMD代码显然难以阅读。 即使遵循每一项软件工程最佳实践,也是如此,例如命名,封装,const正确性(并使副作用显而易见),函数分解等。 即使对于有经验的SIMD程序员也是如此。 与等效的C ++原型代码相比,最佳SIMD代码非常扭曲(请参阅备注)。 扭曲SIMD代码的方法有很多,但是10种这样的尝试中只有1种会获得可接受的快速结果。 …

5
最终价格昂贵
对于在退出函数之前必须进行资源清理的代码,这两种执行方法之间在性能上存在重大差异。 在每个return语句之前清理资源 void func() { login(); bool ret = dosomething(); if(ret == false) { logout(); return; } ret = dosomethingelse(); if(ret == false) { logout(); return; } dootherstuff(); logout(); } 最终清除资源 void func() { login(); try { bool ret = dosomething(); if(ret == false) return; ret = dosomethingelse(); if(ret == …


4
通过使用单元测试超时来衡量方法的性能是一个好主意吗?
在有非功能性需求的项目中,该非功能性需求指定了特定操作的最长时间执行时间,QA必须在精确负载下使用精密硬件检查专用设备上此动作的性能,硬件和负载均在需求中指定。 另一方面,对源代码的一些错误更改可能会严重影响性能。在源代码到达源代码控制并由QA部门验证之前尽早注意到这种负面影响,这可能会因为QA部门报告问题而浪费时间,而开发人员稍后再修复它会造成损失。 为此,这是一个好主意: 要使用单元测试有花了执行相同action²时间的想法ñ倍, 要在C#中通过属性使用每次测试超时[TestMethod, Timeout(200)]? 我期望这种方法会出现几个问题: 从概念上讲,单元测试并非真正做到这一点:它们应仅测试代码的一小部分,仅此而已:既不检查功能需求,也不进行集成测试,也不进行性能测试。 考虑到这些测试不存在初始化和清除功能,或者它们太短而无法影响结果,Visual Studio中的单元测试超时是否真的可以衡量预期的结果? 用这种方法衡量性能很难看。在独立于硬件,负载等因素的任何计算机上运行基准测试,就像进行基准测试一样,表明一种数据库产品总是比另一种数据库产品更快。另一方面,我不希望这些单元测试是确定的结果,也不希望质量检查部门使用这些东西。这些单元测试将仅用于提供有关预期性能的一般概念,并且实质上是在提醒开发人员,他的最后修改破坏了某些内容,从而严重影响了性能。 对于这些测试,无法进行测试驱动开发(TDD)。首先,在开始实施代码之前它将如何失败? 性能测试太多将影响运行测试所需的时间,因此此方法仅限于短期操作。 考虑到这些问题,如果将此类单元测试与质量保证部门的实际性能指标结合使用,我仍然觉得很有趣。 我错了吗?还有其他问题使其完全不能使用单元测试吗? 如果我错了,那么在源代码到达源代码控制并由质量检查部门验证之前,警告开发人员该源代码的更改严重影响性能的正确方法是什么? ¹实际上,单元测试只能在具有相当硬件性能的开发人员PC上运行,从而缩小了永远无法通过性能测试的最快计算机与永远无法通过性能测试的最慢计算机之间的差距。 ²实际上,我的意思是一段相当短的代码,需要花费几毫秒来运行。

10
面向对象真的会影响算法性能吗?
面向对象已经帮助我实现了许多算法。但是,面向对象的语言有时会引导您采用“直接”方法,并且我怀疑这种方法是否总是一件好事。 OO在快速轻松地编码算法方面确实很有帮助。但是对于基于性能的软件(即程序执行速度有多快),此OOP会对它不利吗? 例如,首先将图节点存储在数据结构中似乎“直截了当”,但是如果Node对象包含许多属性和方法,这会导致算法变慢吗? 换句话说,在许多不同对象之间的许多引用,或者使用许多类中的许多方法,是否可能导致“繁重的”实现?

5
是否应该测试算法复杂度?如果是这样,怎么办?
假设我正在实现一些简单的操作,例如搜索排序的列表/数组。该函数(在c#中)看起来类似于: static int FindIndex(int[] sortedList, int i); 我可以根据功能来实现和测试它,但是出于显而易见的原因,我通常宁愿二进制搜索胜于线性搜索或某些故意的愚蠢行为。 所以我的问题是:我们是否应该尝试编写能够在算法复杂度方面保证性能的测试,如果可以,如何做? 我已经开始在这个问题的“您应该”部分的两边都进行争论,但是我想看看人们在没有我的争论的情况下会怎么说。 就“如何”而言,这变得非常有趣:)您可以看到参数化比较运算符并进行测试,该测试的比较运算符对比较进行计数或类似的操作。但是仅仅因为你能做并不意味着你应该... 有没有其他人考虑过(可能)?谢谢。

4
功能范式与底层硬件是否过于分散,以至于总体上效率不高?
受到SO中一个问题的启发:https://stackoverflow.com/questions/6623391/how-to-gain-control-of-a-5gb-heap-in-haskell 关于FP的众多优点和缺点可能是一个漫长的辩论,但就目前而言,我想将FP 的范围缩小到现代硬件上FP的主要效率。 论文: 功能范式意味着不变性和无状态性(?),但是我们运行功能性程序的硬件是有状态的有限自动机。将“纯功能”程序转换为“有状态硬件”表示形式后,程序员几乎无法控制,带来了开销(?),并限制了硬件功能(?)的使用。 我在质疑的陈述中是对还是错? 是否可以证明FP确实/不暗示对现代通用计算机体系结构的主要性能损失? 编辑: 正如我已经在回答某些评论时所说的那样,问题不在于实现性能和细节。这与是否存在主要开销有关,在有状态自动机上运行FP可能会带来这些开销。

4
您最喜欢的按位技术是什么?[关闭]
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案会得到事实,参考或专业知识的支持,但是这个问题可能会引起辩论,争论,民意调查或扩展讨论。如果您认为此问题可以解决并且可以重新提出,请访问帮助中心以获取指导。 7年前关闭。 已锁定。该问题及其答案被锁定,因为该问题是题外话,但具有历史意义。它目前不接受新的答案或互动。 几天前,StackExchange成员Anto询问了按位运算符的有效用法。我说过,移位比将整数除以2的幂更快。StackExchange成员Daemin反驳说,右移带来了负数问题。 那时,我还没有真正考虑过将带符号整数用于移位运算符。我主要在底层软件开发中使用了该技术。因此,我总是使用无符号整数。C对无符号整数执行逻辑移位。执行逻辑右移时,无需注意符号位。空位用零填充。但是,当右移有符号整数时,C执行算术移位运算。空位用符号位填充。此差异导致负值四舍五入为无穷大而不是被舍弃为零,这与有符号整数除法不同。 经过几分钟的思考,得出了第一手的解决方案。该解决方案在移位之前有条件地将负值转换为正值。在执行移位操作后,值将有条件地转换回其负数形式。 int a = -5; int n = 1; int negative = q < 0; a = negative ? -a : a; a >>= n; a = negative ? -a : a; 该解决方案的问题在于,通常将条件赋值语句转换为至少一个跳转指令,并且在不对两个指令路径都进行解码的处理器上,跳转指令可能会非常昂贵。必须两次重新灌注指令流水线才能很好地降低通过分频获得的任何性能提升。 综上所述,我在周六醒来,回答了条件分配问题。我们在执行算术移位运算时遇到的舍入问题仅在使用二进制补码表示形式时发生。它不会以补码表示出现。该问题的解决方案包括在执行移位操作之前将二进制补码值转换为一个二进制补码值。然后,我们必须将一个人的补码值转换回一个两个人的补码值。令人惊讶的是,我们可以执行这组操作,而无需在执行移位操作之前有条件地转换负值。 int a = -5; int n = 1; register int sign …

2
共享缓存-无效的最佳做法
我想知道什么是使缓存对象无效/更新的更好方法。 先决条件 具有远程Memcached服务器(用作多个应用程序的缓存) 所有服务器均由azure托管(关联区域,相同的数据中心) 缓存对象的大小范围从200字节到50 KB 方法1(尽快存储在缓存中) 创建对象A->存储在数据库中并存储在缓存中 客户端请求的对象A->检查缓存是否存在,否则从数据库中获取并存储在缓存中 对象A更新->存储在数据库中,存储在缓存中 方法1似乎更简单。如果创建了某些内容,请尽快放入缓存。不管有人会需要它。 方法2(惰性缓存存储) 创建对象A->存储在数据库中 客户端请求的对象A->检查缓存是否存在,否则从数据库中获取并存储在缓存中 对象A更新->存储在数据库中,删除键在缓存中 方法2似乎更了解内存。在这种方法中,只有请求的项目才进入缓存。 问题1:考虑到性能,哪种方法更好?内存和CPU都不算在内。 问题2:我的想法是过早的优化吗? 问题3:还有其他想法吗?其他方法?

5
没有Dispose()SqlConnections有多糟糕?
就个人而言,如果我在使用语句中不放置实现IDisposable的ADO对象,就会陷入蜂巢。但是根据我目前的合同,我发现他们自己的企业框架“数据访问提供程序”代码不会1)实现IDisposable和2)在任何时候都对它使用的任何东西调用Dispose()。用户一直在抱怨大量使用此框架进行数据访问的Winforms应用程序中的性能问题,尽管代码中还有很多其他问题可能会影响性能,但是这只是让我大叫,甚至更多。比其他人低垂的果实。 因此,除了说出“有某种原因而丢弃在这里,要使用它”之类的话,我还能告诉这些人说服他们这确实是真的吗?

7
将高频事件保存到连接限制受限的数据库中
我们有一种情况,我必须处理大量涌入服务器的事件,平均每秒大约1000个事件(峰值可能是2000个)。 问题 我们的系统托管在Heroku上,并使用相对昂贵的Heroku Postgres DB,该数据库最多允许500个DB连接。我们使用连接池从服务器连接到数据库。 事件传入的速度快于数据库连接池无法处理的速度 我们遇到的问题是事件的发生速度快于连接池无法处理的速度。到一个连接完成从服务器到DB的网络往返时,它可以释放回池中,而不是n其他事件。 最终,事件堆积起来,等待保存,并且由于池中没有可用的连接,它们超时并且整个系统变得无法运行。 我们已经通过以较慢的速度从客户端发出有问题的高频事件来解决紧急情况,但是我们仍然想知道在需要处理高频事件时如何处理这种情况。 约束条件 其他客户端可能希望同时读取事件 其他客户端连续请求使用特定密钥读取所有事件,即使它们尚未保存在数据库中也是如此。 客户端可以查询GET api/v1/events?clientId=1并获取客户端1发送的所有事件,即使这些事件尚未保存到DB中也是如此。 是否有有关如何处理此问题的“教室”示例? 可能的解决方案 使事件排队在我们的服务器上 我们可以在服务器上排队事件(队列的最大并发性为400,因此连接池不会用完)。 这是个坏主意,因为: 它将耗尽可用的服务器内存。堆积的排队事件将消耗大量RAM。 我们的服务器每24小时重启一次。这是Heroku施加的硬限制。当事件排队时,服务器可以重新启动,导致我们丢失排队的事件。 它在服务器上引入状态,从而损害了可伸缩性。如果我们有一个多服务器设置,并且客户端要读取所有已排队+保存的事件,则我们将不知道已排队事件在哪台服务器上。 使用单独的消息队列 我假设我们可以使用消息队列(例如RabbitMQ吗?),在其中将消息泵入其中,另一方面,还有另一台服务器仅处理将事件保存在DB上。 我不确定消息队列是否允许查询排队的事件(尚未保存),因此,如果另一个客户端想要读取另一个客户端的消息,我只能从数据库中获取已保存的消息,并从队列中获取待处理的消息。并将它们连接在一起,这样我就可以将它们发送回读取请求客户端。 使用多个数据库,每个数据库使用中央数据库协调器服务器保存一部分消息,以管理它们 不过,我们的另一个解决方案是使用多个数据库,并使用一个中央“ DB协调器/负载平衡器”。接收到事件后,此协调器将选择一个数据库来写入消息。这应该允许我们使用多个Heroku数据库,从而将连接限制提高到500 x数据库数。 在进行读取查询时,此协调器可以SELECT向每个数据库发出查询,合并所有结果,然后将其发送回请求读取的客户端。 这是个坏主意,因为: 这个主意听起来像是...太设计了吗?管理(备份等)也将是一场噩梦。它的构建和维护非常复杂,除非绝对必要,否则听起来像是违反了KISS。 它牺牲了一致性。如果我们遵循这个想法,那么跨多个数据库进行事务是不可行的。

5
Java堆分配比C ++更快
我已经在SO上发布了这个问题,它的确可以。不幸的是它关闭了(只需要一票就可以重新打开),但是有人建议我将它发布在这里,因为它更合适,因此以下内容实际上是该问题的粘贴内容 我正在阅读对此答案的评论,并且看到了这句话。 对象实例化和面向对象功能使用起来非常快(在许多情况下,它们比C ++更快),因为它们是从一开始就设计的。且收集速度很快。即使在大多数优化的C代码方面,标准Java在这一领域也优于标准C / C ++。 一位用户(我可能会添加非常高的代表)大胆地捍卫了这一主张,并指出 Java中的堆分配比C ++更好 并添加了该语句来捍卫Java中的集合 与Java集合相比,Java集合与C ++集合相比速度更快,这在很大程度上归因于内存子系统的不同。 所以我的问题是,这是否真的是真的,如果是的话,为什么Java的堆分配这么快?

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.