有趣的结果是与C ++的速度比较 [英] Interesting results in speed comparison with C++

查看:75
本文介绍了有趣的结果是与C ++的速度比较的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我编写了两个简单的测试程序,它们在C#(Visual Studio 2005)中首次进行了十亿次迭代的虚拟方法调用:


Thing t = new DerivedThing();

for(System.Int64 n = 0; n< 10000000000; n ++)

t.method();


然后在C ++中(使用Visual C ++ 2005):


Thing * t = new DerivedThing();

for(__ int64 n = 0; n <10000000000L; n ++)

t-> method();


....在每种情况下都有适当的声明(抽象

基类)和DerivedThing(方法增加一个计数器)。


C#花了47秒,C ++花了58秒。两者都是发布版本。


现在,鉴于虚拟方法调度的C ++实现非常接近金属,这必然意味着当C#

版本运行时,没有发生虚拟方法调度。

CLR JIT必须内联方法调用,对吗? (我查看了IL

并且它没有被C#编译器内联。)


然后我尝试移动里面的DerivedThing的分配循环

- 对于C ++程序,这也意味着在

方法调用之后加上''删除t''。请注意,DerivedThing是C#中的类,而不是结构,

并且它包含一些数据。


C#花了13秒,C ++花了175秒。我对此感到有些震惊,

所以再跑几次,结果相同。


我想也许JIT看着我'我正在使用该对象和

意识到我不会在

循环范围之外保留对它的引用,所以它不需要以与长期存在的对象相同的方式分配在垃圾上。/ b
收集的堆。当然要知道这一点,它必须查看方法()的代码,因为它可以在某个地方隐藏''this''引用。


所以我修改了DerivedThing的方法,所以它将''this''参考

存储在一个静态成员中,但仅在第十四次(out)十亿!)

它被称为。现在CLR必须在每次循环时分配一个垃圾收集

对象,对吗?


但这只是将运行时间增加到16秒,仍然
比C ++结果的10%少。


所以也许它内联方法(),然后查看它的作用和

完全重写它以产生相同的效果而不分配
亿个对象?


是否有任何文章会告诉我什么是CLR''垃圾

收集堆(和/或JIT)实际上是在做这种情况吗?怎么

比非垃圾收集的C +

+堆快十倍?

I wrote two trivial test programs that do a billion iterations of a
virtual method call, first in C# (Visual Studio 2005):

Thing t = new DerivedThing();
for (System.Int64 n = 0; n < 10000000000; n++)
t.method();

Then in C++ (using Visual C++ 2005):

Thing *t = new DerivedThing();
for (__int64 n = 0; n < 10000000000L; n++)
t->method();

.... with appropriate declarations in each case for Thing (abstract
base class) and DerivedThing (method increments a counter).

C# took 47 seconds, C++ took 58 seconds. Both were release builds.

Now, given that the C++ implementation of virtual method dispatch is
very "close to the metal", this must mean that by the time the C#
version is running, there is no virtual method dispatch happening. The
CLR JIT must be inlining the method call, right? (I looked at the IL
and it''s not being inlined by the C# compiler).

Then I tried moving the allocation of the DerivedThing inside the loop
- for the C++ program this also meant putting a ''delete t'' after the
method call. Note that DerivedThing is a class in C#, not a struct,
and it holds some data.

C# took 13 seconds, C++ took 175 seconds. I was a bit shocked by this,
so ran both a few more times, with identical results.

I thought maybe the JIT looks at what I''m doing with the object and
realises that I''m not holding onto a reference to it outside of the
loop scope, and so it doesn''t need to be allocated on the garbage
collected heap in the same way as a long-lived object. Of course to
know that, it would have to look at the code of method(), because it
could be stashing the ''this'' reference somewhere.

So I modified DerivedThing''s method so it stored the ''this'' reference
in a static member, but only on the forteenth time (out of a billion!)
that it was called. Now the CLR has to allocate a garbage collected
object each time around the loop, right?

But this merely increased the running time to 16 seconds, still less
than 10% of the C++ result.

So maybe it inlines method(), then looks at what it does and
completely rewrites it to produce the same effect without allocating a
billion objects?

Are there any articles that will tell me what the CLR''s garbage
collected heap (and/or the JIT) is actually doing in this case? How
can it be more than ten times faster than the non-garbage collected C+
+ heap?

推荐答案

9月7日,12:30,Daniel Earwicker< daniel.earwic ... @ gmail.comwrote:
On 7 Sep, 12:30, Daniel Earwicker <daniel.earwic...@gmail.comwrote:

I写了两个琐碎的测试程序,它们在C#(Visual Studio 2005)中进行了十亿次迭代的
虚拟方法调用:
I wrote two trivial test programs that do a billion iterations of a
virtual method call, first in C# (Visual Studio 2005):



哎呀,我应该说:原来的程序做了100亿次b
迭代,修改后的版本(做堆分配)做了1亿美元。否则结果真的会疯狂!

Oops, I should have said: the original programs did 10 billion
iterations, the modified versions (that do heap allocation) did 1
billion. Otherwise the results really would be crazy!


" Daniel Earwicker" < da ************** @ gmail.comschrieb im Newsbeitrag

新闻:11 **************** ******@w3g2000hsg.googlegro ups.com ...
"Daniel Earwicker" <da**************@gmail.comschrieb im Newsbeitrag
news:11**********************@w3g2000hsg.googlegro ups.com...

>我写了两个琐碎的测试程序,完成了十亿次迭代>
虚拟方法调用,首先在C#中(Visual Studio 2005):


Thing t = new DerivedThing();

for(System。 Int64 n = 0; n <10000000000; n ++)

t.method();


然后在C ++中(使用Visual C ++ 2005):


Thing * t = new DerivedThing();

for(__ int64 n = 0; n< 10000000000L; n ++)

t - >方法();


...在每种情况下都有适当的声明(抽象

基类)和DerivedThing(方法增加一个计数器) )。


C#花了47秒,C ++花了58秒。两者都是发布版本。


现在,鉴于虚拟方法调度的C ++实现非常接近金属,这必然意味着当C#

版本运行时,没有发生虚拟方法调度。

CLR JIT必须内联方法调用,对吗? (我查看了IL

并且它没有被C#编译器内联。)
>I wrote two trivial test programs that do a billion iterations of a
virtual method call, first in C# (Visual Studio 2005):

Thing t = new DerivedThing();
for (System.Int64 n = 0; n < 10000000000; n++)
t.method();

Then in C++ (using Visual C++ 2005):

Thing *t = new DerivedThing();
for (__int64 n = 0; n < 10000000000L; n++)
t->method();

... with appropriate declarations in each case for Thing (abstract
base class) and DerivedThing (method increments a counter).

C# took 47 seconds, C++ took 58 seconds. Both were release builds.

Now, given that the C++ implementation of virtual method dispatch is
very "close to the metal", this must mean that by the time the C#
version is running, there is no virtual method dispatch happening. The
CLR JIT must be inlining the method call, right? (I looked at the IL
and it''s not being inlined by the C# compiler).



两个版本都需要做虚拟调度,因为名为

的方法取决于实例的类型,而不是变量的类型。两个

编译器都有一个简单的机会来优化远程,因为

atual类型很容易知道,并且总是相同。也许其中一个更聪明。

我们必须查看运行时代码才能知道这个。


Christof

Both versions need to do a virtual dispatch, because the method called
depends on the type of the instance, not on the type of the variable. Both
compilers have an easy chance to optimize the dispath away, because the
atual type is easy known and allways the same. Maybe one of them is smarter.
We would have to look at the runtime code to know this.

Christof

< br>

" Christof Nordiek" < cn@nospam.deschrieb im Newsbeitrag

news:eK ************** @ TK2MSFTNGP04.phx.gbl ...
"Christof Nordiek" <cn@nospam.deschrieb im Newsbeitrag
news:eK**************@TK2MSFTNGP04.phx.gbl...

两个编译器都有一个简单的机会来优化调度,因为

这个类型很容易知道并且总是相同的。
Both compilers have an easy chance to optimize the dispath away, because
the atual type is easy known and allways the same.



这可以通过将赋值放在

方法之外并使用派生类型的参数来防止。


Christof

This maybe could be prevented by putting the assignment outside of the
method and using a parameter of the derived type.

Christof


这篇关于有趣的结果是与C ++的速度比较的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆