假设我有一个包含许多小函数的c++代码,在每个函数中,我通常需要一个矩阵浮点M1(n,p),其中n,p在运行时是已知的,以包含中间计算的结果(不需要初始化M1,只是为了声明它,因为每个函数都会覆盖M1的所有行)。
这样做的部分原因是每个函数都在一个不能修改的原始数据矩阵上工作,所以许多操作(排序、去含义、拆分)需要在“别处”上完成。
在每个函数中创建临时M1(n,p)是更好的做法,还是在main()中一次性地将其作为一种桶传递给每个函数,每个函数可以将其用作碎片空间?
N和p通常比较大,n为10^2-10^4,p为5-100。
(最初发布在codereview stackexchange,但搬到了这里)。
最好的
发布于 2012-03-02 16:06:13
expensive.
我建议你自然地编写代码,考虑到#3作为未来的可能性。也就是说,不要为了中间计算而引用矩阵缓冲区来加速创建临时库。创建临时变量并按值返回它们。正确性和良好、清晰的界面是第一位的。
这里的主要目标是分离矩阵的创建策略(通过分配器或其他方法),这为您提供了喘息的空间,以便在不更改太多现有代码的情况下进行事后优化。如果你可以只修改相关函数的实现细节,或者更好的是,只修改矩阵类的实现,那么你真的很幸运,因为这样你就可以在不改变设计的情况下自由地进行优化,而且从效率的角度来看,任何允许这样做的设计都是完整的。
警告:只有当你真的想最大限度地利用每个周期时,才会使用下面的方法。理解#4并让自己成为一个好的分析员是很重要的。同样值得注意的是,与优化堆分配相比,优化这些矩阵算法的内存访问模式可能会做得更好。
如果需要优化内存分配,可以考虑使用一些通用的方法来优化它,比如每个线程的内存池。例如,你可以让你的矩阵接受一个可选的分配器,但我在这里强调的是可选的,我还想先用一个简单的分配器实现来强调正确性。
换句话说:
更好的做法是在每个函数中声明M1(n,p),或者更确切地说,在
()中一次性地将其作为一种桶传递给每个函数,每个函数可以将其用作碎片空间。
继续,在每个函数中创建一个临时的M1。尽量避免要求客户制作一些对他/她没有意义的矩阵,只为了计算中间结果。这将暴露优化细节,这是我们在设计接口时不应该做的事情(隐藏所有客户端不应该知道的细节)。
相反,如果您绝对希望该选项加速这些临时程序的创建,则应专注于更一般的概念,如可选分配器。这符合实际的设计,比如使用std::set
std::set<int, std::less<int>, MyFastAllocator<int>> s; // <-- okay尽管大多数人只是这样做:
std::set<int> s;在您的例子中,它可能只是: M1 my_matrix(n,p,alloc);
这是一个细微的区别,但分配器是一个比缓存矩阵更通用的概念,否则缓存矩阵对客户端没有任何意义,除了函数需要某种缓存来帮助它们更快地计算结果之外。请注意,它不一定是通用分配器。它可能只是传递给矩阵构造函数的预先分配的矩阵缓冲区,但从概念上讲,将它分离出来可能更好,因为它对客户来说更不透明。
此外,构造这个临时矩阵对象还需要注意不要跨线程共享它。这是另一个原因,如果你真的走优化路线,你可能想要推广一下这个概念,因为像矩阵分配器这样更一般的东西可以考虑线程安全,或者至少通过设计更多地强调每个线程应该创建一个单独的分配器,但原始矩阵对象可能不能。
只有当你首先关心你的界面的质量时,上述方法才有用。如果没有,我会推荐使用Matthieu的建议,因为它比创建一个分配器简单得多,但我们都强调使加速版本成为可选的。
发布于 2012-03-02 15:47:49
不要使用过早的优化。创建一些工作正常且运行良好的东西,如果它表现得很慢,可以在以后进行优化。
(顺便说一句,我也不认为stackoverflow是合适的地方)。
实际上,如果您想要加快应用程序在大型矩阵上的操作速度,那么使用并发将是您的解决方案。如果你使用并发,如果你有一个大的全局矩阵,你可能会遇到更多的麻烦。
从本质上说,这意味着即使你有足够的内存,你也永远不能同时进行多个计算。
矩阵的设计需要是最优的。我们必须看一下这个设计。
因此,我通常会在你的代码中说,不,不要创建一个大的全局矩阵,因为它听起来与你想要做的事情是错误的。
发布于 2012-03-02 15:47:30
首先尝试定义函数内部的矩阵。这绝对是更好的设计选择。但是如果你得到了你不能承受的性能损失,我认为“每次引用传递缓冲区”是可以的,只要你记住这些函数不再是线程安全的。如果在任何时候使用线程,每个线程都需要自己的缓冲区。
https://stackoverflow.com/questions/9529614
复制相似问题