哪个性能更好?静态与对象

3
我设计了一个用于合并和拆分大文件(约4GB)的C#控制台应用程序,采用面向对象设计。它涉及读写xml、平面文件和图像。我有针对读取器和写入器的类。
合并需要大约00:12的时间,而拆分需要超过04:30小时的时间。然后我通过将输出文件分布到子目录中而不是使用单个目录来增强了拆分性能,使其达到了00:50。
我的老板要求我将所有内容转换为静态过程式编程,但不包括对象。他说合并需要00:12,而拆分需要00:50不平衡。他希望通过转换为静态方法在00:30内完成拆分。
现在我知道根据这里的说明,静态调用更快。但是我不同意所有静态方法都会更好,因为我将不得不在方法中使用“ref”和“out”参数。
我的问题是:
  1. 将文件拆分成子目录比使用单个输出目录快得多的原因是什么?(即对于大量文件>200,000)
  2. 除了将代码从对象转换为静态以实现更高的性能外,还有更好的方法吗?

1
将文件分成子目录的原因比使用单个输出目录更快的原因是什么?(即对于大量文件> 200,000)。很难回答,没有你的源代码。这可能是在循环中列出或搜索特定文件而不是仅迭代它们(如果可能)的原因。 - okutane
7个回答

13

你有对程序进行性能分析吗?

你应该对代码进行性能分析。对象是快速的,不优化的代码非常慢。

在你进行优化之后,这个任务无论如何都会受到I/O限制(这意味着它大部分时间都在等待磁盘获取另一部分数据)。

而且,你的老板最好做老板该做的事情,比如打高尔夫球或者闲逛,而不是跟你扯关于软件设计的废话。因为你不是为他打高尔夫球,对吧?


1
向你的老板请求类似这样的东西:http://www.red-gate.com/products/ants_performance_profiler/index.htm - tanascius
你应该对你的代码进行性能分析。 对象是快速的,不优化的代码则非常缓慢。 - alamar
"因为你不是在替他打高尔夫球,对吧?" 太好了! - okutane

11

实例调用和静态调用的差异微小到我可以放心地打赌,它与您的性能问题毫无关系。是的,从技术上讲,静态调用要快一些(微乎其微),但与您正在进行的所有文件IO相比,这根本算不了什么。就像已经说过的那样 - 对您的代码进行分析,不要担心这种事情(过早优化)。最有可能的瓶颈是集合性能不佳,也许可以通过使用字典等方法来解决。

时间:

static: 154ms
instance: 156ms

那么在 5000 万次调用中有 2 毫秒的差异!可以忘记它了...

基于:

class Program
{
    static void Main()
    {
        StaticMethod(); // JIT
        Program p = new Program();
        p.InstanceMethod(); // JIT

        const int LOOP = 50000000; // 50M
        Stopwatch watch = Stopwatch.StartNew();
        for (int i = 0; i < LOOP; i++) StaticMethod();
        watch.Stop();
        Console.WriteLine("static: " + watch.ElapsedMilliseconds + "ms");

        watch = Stopwatch.StartNew();
        for (int i = 0; i < LOOP; i++) p.InstanceMethod();
        watch.Stop();
        Console.WriteLine("instance: " + watch.ElapsedMilliseconds + "ms");
    }
    [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
    void InstanceMethod() { }
    [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
    static void StaticMethod() { }
}

编辑:

如果我们假设(例如)每调用20次就创建一个新方法(if (i%20 == 0) p = new Program();),那么指标将发生改变:

static: 174ms
instance: 873ms

再次强调-在 5000 万次以上的调用时,并且仍然不到一秒钟,远远不足以表明瓶颈!


1
你的做法稍微有些不对,实例示例应该包含一些对象实例化(例如,在每个第十次迭代中,p = new Program())。 - alamar
1
有些肯定是这样的,否则仍然几乎静态。 - alamar

6
你的任务听起来应该是IO密集型,而不是CPU密集型。通过删除适当的OO设计进行微调优化将是疯狂的行为。通常情况下,静态方法和实例方法之间的差异是不可测量的(即使存在)。正如alamar所说,在进一步操作之前,您应该对应用程序进行性能分析。Microsoft提供了一个免费的分析器,或者您可以使用JetBrains dotTrace分析器。当然还有其他工具-这是我使用过的两个工具。
只是作为指示,判断它是IO密集型还是CPU密集型,如果在应用程序运行时运行任务管理器,进程占用了多少CPU?并且整个过程中磁盘是否一直在忙碌?
将大量文件放在一个目录中会减慢对该目录的访问速度,但仅当您实际创建或打开文件或列出目录中的文件时才会出现这种情况。我很惊讶它确实会有那么大的影响。然而,在一个目录中有200,000个文件听起来本来就不可管理。使用分层方法可能更好地使用这些文件之后。

为什么你的老板认为合并和拆分应该花费相同的时间呢?


如何使用 Microsoft CLR 内存分析器对应用程序的执行性能进行分析? - okutane
它不仅是一个内存分析器,还提供调用图,因此您可以看到是否多次调用某些方法。 - Jon Skeet

3
我可以回答第一点:在单个目录中拥有许多文件会导致性能下降。这与你的代码无关,而是一个Windows问题(或者NTFS问题,我不确定)。将文件分散到不同的子目录下确实可以显著提高性能。
至于第二点,我非常怀疑使用静态方法会有很大的差别。使用静态方法更快,但只是稍微地快一点。我们在谈论微秒级别的速度。可能还有其他问题。就像alamar所说的那样,只有一种方法可以找出来,那就是对代码进行分析。
您可以使用Ants等工具对代码进行分析,查看哪些操作是瓶颈。它可以列出程序中所有方法花费的时间,因此您可以看到什么需要最长时间,这可能真的是任何事情。但这样你至少知道了需要优化的内容。

2

我的回答是:

  1. 根据你的操作系统和文件系统,性能在20-30k个文件/子文件夹后开始下降。这是一个不可避免的事实。NTFS性能和大量文件和目录

  2. 声称非面向对象的代码比面向对象的代码更快是荒谬的。在对代码进行分析之前,你无法知道性能瓶颈在哪里。请参考此问题的答案以获得有用的信息:性能反模式


0

许多文件系统在目录中的条目数量超过一定限制时会出现性能问题。您使用的是哪一个?

如果您在程序的调试版本中添加日志记录功能,您可以得到最耗时的地方的指示。这就是优化应该进行的地方。


0
1. 没有了解你的文件系统,无法回答这个问题。但是正如其他人所指出的,FS通常并不针对大量折叠的目录树进行优化。 2. 我认为因为可能(你还没有进行性能分析)提高10%的速度而拒绝面向对象编程是荒谬的,特别是当网页上说“请不要过于字面理解这些数据”的时候。 最后,尽管你没有提供太多信息,但我认为这种“不平衡”并不奇怪。写入速度较慢,有时会显著影响效率。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接