银河

SKYIV STUDIO

  博客园 :: 首页 :: 博问 :: 闪存 :: :: :: 订阅 订阅 :: 管理 ::

最近一段时间,我在 Timus Online Judge 网站做 ACM 题

首先,让我们看一下 Timus 1114. Boxes

这道题要求计算出将两种颜色的球放到盒子中的各种组合的数目。我们发现用同样的算法,C# 程序居然比 C++ 程序慢 62 倍。

真的是 C# 应用程序的性能就一定很差吗?不是的。实际上在这道题中,使用的算法是非常高效的。上面的 0.001 秒和 0.062 秒已经分别是 C/C++ 程序和 C# 程序在 Timus Online Judge 网站运行的最短时间了。毕竟 C# 是托管的应用程序,要在 CLR 环境中运行,第一次运行时需要进行 JIT 编译。最小的基本开销要比 C/C++ 应用程序大。

接着,我们再来看看 Timus 1219. Symbolic Sequence

这道题要求输出满足给定条件的一百万个小写拉丁字母。还是使用同样的算法,C# 程序比 C++ 程序慢 15 倍,比 C 程序慢 64 倍。

这次,不能用最小的基本开销来解释了,因为这些程序运行的时间已经不算很短了。但是,这道题还是有些特别的,它的时间主要花费在输出大量的(一百万个)字符上。C# 程序是调用了一百万次 Console.Write() 方法,C++ 程序调用了一百万次 std::cout << c 语句,C 程序调用了一百万次 putchar() 函数。应该是这三种方法的不同效率造成的差异。如果把本题的算法稍做修改,使 C# 程序只调用一次 Console.Write() 方法输出全部一百万个字符,则其运行时间从 0.968 秒下降到 0.093 秒。

现在,让我们来看看 Timus 1152. The False Mirrors


这道题说述消灭怪物的故事,要求计算出故事中主角受到的最小伤害。还是使用同样的算法,我们终于看到 C# 程序和 C++ 程序的运行时间差不多了。

不过,坦白的说,实际上这道题我使用的算法不是最优的。这道题最优的算法使用 C++ 语言实现,运行时间只需要 0.001 秒。我不知道该算法是什么,如有谁知道的麻烦告诉我一下。:)

由于大多数 ACM 题目使用好的算法时需要的时间是很短的,所以如果用 C# 语言做题的话,基本上会发现比 C/C++ 语言慢很多,但是一般来说也不会超时,除非你使用的算法很差。下面就有一个例子,就是 Timus 1081. Binary Lexicographic Sequence


这道题要求给出第 K (0 < K < 109) 个 N (0 < N < 44) 位二进制数,该二进制数不得有相邻的“1”。在 Accepted 的 C# 和 C++ 程序中,使用了时间复杂度为 O(N) 的算法。而在 Time limit exceeded 的 C++ 程序中,使用了时间复杂度约为 O(1.618N+2) 的算法。

所以关键还是算法,而不在于程序设计语言。

何况,托管应用程序的性能在某些应用场合实际上有可能超过非托管的应用程序。例如,当 JIT 编译器在运行时将 IL 代码编译成本地代码时,编译器对执行环境的认识比非托管编译更加深刻。

JIT 编译器能判断应用程序是否运行在一个 Core 2 Duo 的 CPU 上,并生成相应的本地代码来利用 Core 2 Duo 支持的任何特殊指令。通常,非托管应用程序是针对具有最小功能集合的 CPU 编译的,不会使用可提升应用程序性能的特殊指令。

JIT 编译器可能判断一个特定的测试在运行它的机器上是否总是失败。例如,假定某个方法包含了一段代码判断主机上的 CPU 数多于一个时才执行的语句。如果主机上只有一个 CPU,则上述代码将导致 JIT 编译器不生成任何 CPU 指令。在这种情况下,本机代码将针对主机进行优化,最终的代码变得更小,执行得更快。

应用程序运行时,CLR 能评估代码的执行,并将 IL 重新编译成本地代码。重新编码的代码可能重新组织,根据刚才观察到的执行模式,减少不正确的分支预测。

posted on 2008-07-02 23:15  银河  阅读(11046)  评论(32编辑  收藏  举报