在数以千计的处理器上运行 10 小时的数字代码中,我有一个基类 (Mesh),其方法被命中数百万次到 100 到 1000 次。目前有两个 (Mesh_A, Mesh_B) 派生类,但最终会扩展到三个或四个。用户代码直到运行时才能知道其指向 Mesh 的指针实际上是 Mesh_A 还是 Mesh_B,但对于运行的其余部分,它永远不会改变。
当前实现:
// Base class
class Mesh {
...
virtual const Point& cell_centroid(int c) = 0;
}
// derived class A
class MeshA : public Mesh {
...
Point& cell_centroid(int c) { return cell_centroids_[c]; }
}
// derived class B
class MeshB : public Mesh {
...
Point& cell_centroid(int c) { return other_framework_->cell_centroid(c); }
}
// typical user class
class User {
User(Mesh* mesh) : mesh_(mesh) {}
void evalFunction() {
for (int c=0; c!=mesh_->num_cells(); ++c) {
double result = func(mesh_->cell_centroid(c));
...
}
}
// Other methods which use mesh_->cell_centroid() very often, and in different ways.
}
之前MeshA是唯一的Mesh,没有基类,重击的方法都是内联的。分析表明,使用虚拟方法对运行时多态性的更改(可能是由于内联的丢失?)导致了约 15% 的命中率,这是行不通的。
我一直在讨论静态多态性和其他想法,但我很想听听关于如何以合理可持续的方式避免这种打击的想法。
想法 1:粗化虚函数以分摊开销。一种想法是尝试将这些方法的所有“调用模式”封装在一个虚拟方法中,将虚拟提升到更粗略的级别,同时将细粒度方法保持为非虚拟。例如,在上面的示例中,可以将函数指针传递给实现循环的 Mesh 的新虚拟方法,返回 double 组并在其中调用非虚拟的内联 cell_centroid() 方法。
// Base class
class Mesh {
...
virtual void evalFunction(double (*func)(Point&), std::vector<double>* result) = 0;
}
// derived class A
class MeshA : public Mesh {
...
void evalFunction(double (*func)(Point&), std::vector<double>* result) {
for (int c=0; c!=num_cells(); ++c) (*result)[c] = (*func)(cell_centroid(c));
}
Point& cell_centroid(int c) { return cell_centroids_[c]; }
}
// similar for B
// typical user class
class User {
User(Mesh* mesh) : mesh_(mesh) {}
void evalFunction() {
m_->evalFunction();
}
}
我有点担心这会使 Mesh 接口(interface)变得庞大——我没有可以轻松封装的单一访问模式(如示例)。我的猜测是,对于当前 Mesh 类 (15-20) 中的每个虚方法,我会有 3 或 4 种不同的“调用模式”,并且 Mesh 的接口(interface)会爆炸。有多种“用户”类,虽然有时以相同的方式使用 Mesh,但并非总是如此,我不想将自己局限于几种模式。
想法 2: 使用 Mesh_T 模板化所有用户代码.编写一个创建 User<MeshA> 的工厂或 User<MeshB>实例取决于运行时信息。这有点令人担心,因为这实际上意味着我的整个代码都是模板化代码,编译时间会增加,错误会更难调试等等。将触及大型代码库。
想法 3: 在我看来,应该能够在运行开始时解决用户获得的 Mesh 指针实际上是 MeshA 或 MeshB,而不需要执行虚拟表查找并重新获得内联 A 或 B 实现。我不知道这样做的优雅方式基本上不会比想法 1 更糟糕,即 User 中的一堆重复代码与 case/switch。但如果有一种优雅的方式来做到这一点,那将是我的第一选择。
任何关于一个好的选择、更好的想法的想法,或对没有虚拟低级方法的高级类的运行时多态性的其他评论,我们将不胜感激!
最佳答案
前提是我理解正确,mesh_ 将始终是 MeshA 或 MeshB 而不是它们的混合。
//典型的用户类
class User {
User(Mesh* mesh) : mesh_(mesh) {}
template<class dType>
void evalFunction() {
dType *myMesh = dynamic_cast<dType *>(mesh_);
for (int c=0; c!=myMesh _->num_cells(); ++c) {
double result = func(myMesh _->cell_centroid(c));
...
}
}
void evalFunction() {
if (dynamic_cast<MeshA *>(mesh_))
evalFunction<MeshA>();
if (dynamic_cast<MeshB *>(mesh_))
evalFunction<MeshB>();
}
}
evalFunction 选择 A 或 B 模板。
或者
class User {
User(Mesh* mesh) : mesh_(mesh) {}
template<class dType>
void evalFunction(dType *myMesh) {
for (int c=0; c!=myMesh _->num_cells(); ++c) {
double result = func(myMesh _->cell_centroid(c));
...
}
}
void evalFunction() {
MeshA *meshA = dynamic_cast<MeshA *>(mesh_);
if (meshA)
evalFunction<MeshA>(meshA);
MeshB *meshB = dynamic_cast<MeshB *>(mesh_);
if (meshB)
evalFunction<MeshB>(meshB);
}
}
关于c++ - 避免运行时多态性的性能问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34162611/
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0
我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po
尝试通过RVM将RubyGems升级到版本1.8.10并出现此错误:$rvmrubygemslatestRemovingoldRubygemsfiles...Installingrubygems-1.8.10forruby-1.9.2-p180...ERROR:Errorrunning'GEM_PATH="/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/ruby-1.9.2-p180@global:/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/rub
在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/
exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby中使用两个参数异步运行exe吗?我已经尝试过ruby命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何rubygems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除
我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
我的最终目标是安装当前版本的RubyonRails。我在OSXMountainLion上运行。到目前为止,这是我的过程:已安装的RVM$\curl-Lhttps://get.rvm.io|bash-sstable检查已知(我假设已批准)安装$rvmlistknown我看到当前的稳定版本可用[ruby-]2.0.0[-p247]输入命令安装$rvminstall2.0.0-p247注意:我也试过这些安装命令$rvminstallruby-2.0.0-p247$rvminstallruby=2.0.0-p247我很快就无处可去了。结果:$rvminstall2.0.0-p247Search
Sinatra新手;我正在运行一些rspec测试,但在日志中收到了一堆不需要的噪音。如何消除日志中过多的噪音?我仔细检查了环境是否设置为:test,这意味着记录器级别应设置为WARN而不是DEBUG。spec_helper:require"./app"require"sinatra"require"rspec"require"rack/test"require"database_cleaner"require"factory_girl"set:environment,:testFactoryGirl.definition_file_paths=%w{./factories./test/