【问题标题】:benchmark and the cause for difference between c# and java基准测试以及 c# 和 java 之间差异的原因
【发布时间】:2009-06-23 13:00:16
【问题描述】:

我有一个令人费解的情况,我需要专家的意见来解释下面解释的现象的原因。几周前,我举办了一场题为“Java 开发人员概述 .NET”的会议,作为其中的一部分,我编写了一个快速的 C# 类(3.5 框架)来逐行读取文件并写入另一个文件(在迭代中)。由于我的受众是 Java 开发人员,因此我在 Java 类中使用相同的代码进行并排比较。然而,当我在同一台机器上运行这些类时,令我惊讶的是,java 代码的运行速度始终是 C# 代码的两倍。我在 C# 代码中尝试了许多优化来缩小差距,但未能成功。必须有一个解释,我正在寻找可以解释原因的人。我附上了这两个类的源代码供您参考。


Java 类

    public class ReadWriteTextFile {

    static public String getContents(File aFile, String OutPutFileName) {
    StringBuilder contents = new StringBuilder();

    try {
      BufferedReader input =  new BufferedReader(new FileReader(aFile));
      FileReader x = new FileReader(aFile);
      try {
        String line = null;
        while (( line = input.readLine()) != null){
              setContents(OutPutFileName, line + System.getProperty("line.separator"));
        }
      }
      finally {
        input.close();
      }
    }
    catch (IOException ex){
      ex.printStackTrace();
    }

    return contents.toString();
    }

  static public void setContents(String FileName, String aContents)
                                 throws FileNotFoundException, IOException { 
    try {
        FileWriter fstream = new FileWriter(FileName, true);
        BufferedWriter out = new BufferedWriter(fstream);
        out.write(aContents);
             out.close();
    } catch (Exception xe) {
        xe.printStackTrace();
    }
  }
  public static void main (String[] aArguments) throws IOException {

    System.out.println(getDateTime() + ": Started");
    File testFile = new File("C:\\temp\\blah.txt");
         String testFile2 = "C:\\temp\\blahblah.txt";

    for(int i=0; i<100; i++){
         getContents(testFile, testFile2);
     }

    System.out.println(getDateTime() + ": Ended");

  }

  private synchronized static String getDateTime() {
        DateFormat dateFormat = new SimpleDateFormat(
                                        "yyyy/MM/dd HH:mm:ss");
        Date date = new Date();
        return dateFormat.format(date);
    }
}

C#类

class ReadWriteTextFile
{
    static void Main(string[] args)
    {
        System.Diagnostics.Trace.WriteLine(getDateTime() + ": Started");
        String testFile = "C:\\temp\\blah.txt";
        String testFile2 = "C:\\temp\\blahblah.txt";
        for(int i=0; i<100; i++){
            getContents(testFile, testFile2);
        }
        System.Diagnostics.Trace.WriteLine(getDateTime() + ": Ended");
    }

    static public void getContents(String sourceFile, String targetFile) {      
        try {
            using (StreamReader r = File.OpenText(sourceFile))
            {
                String line;
                while ((line = r.ReadLine()) != null)
                {
                    setContents(targetFile, line);
                }
                r.Close();
            }
    }
    catch (IOException ex){
        Console.WriteLine(ex.StackTrace);
    }
  }

  static public void setContents(String targetFile, String aContents)
  {

    try {
        //FileStream fsO = new FileStream(targetFile, FileMode.Append);
        //StreamWriter w = new StreamWriter(fsO);
        FileStream fs = new FileStream(targetFile, FileMode.Append,
                                FileAccess.Write, FileShare.None);
        using (StreamWriter w = new StreamWriter(fs))
        {
            w.WriteLine(aContents + "\n");
        }
    } catch (Exception xe) {
        Console.WriteLine(xe.StackTrace);
    }
  }

  private static String getDateTime() {
      DateTime dt = DateTime.Now;
      return dt.ToString("yyyy/MM/dd HH:mm:ss");
   }
}

【问题讨论】:

  • 也许这是一个简单的例子,“java 可以更快地完成这个特定的事情”。
  • 您使用的是哪个 JDK?是否开启了任何优化?
  • 在运行后立即尝试重新运行 C# 版本。
  • 我亲自动手并广泛使用 C# 和 Java。我尊重这两种语言,我了解 C# 的功能,我相信 C# 几乎可以像 Java 一样高效地完成任务。
  • 我已经尝试立即运行 C# 版本,假设第一次 JIT 需要时间。没有区别。

标签: c# java visual-studio io benchmarking


【解决方案1】:

一方面:在 Java 中,您使用的是平台的默认编码。这很可能是一个固定的“每个字符一个字节”编码,这显然比使用 UTF-8 更简单,而 .NET 默认会这样做。

此外,您在 .NET 中编写 两个 换行符,而在 Java 中只编写 一个

要检查的一件事是您是否受 CPU 限制或 IO 限制。我预计这是受 IO 限制的,但在此之前我当然感到惊讶。

最后,您应该在重新启动后运行每个测试,以尽量从等式中删除磁盘缓存。

【讨论】:

  • 如何关闭 .NET 中的 UTF-* 编码,为什么你说我在 .NET 版本中写了两行????如何检查我是否受 CPU 限制或 IO 限制??
  • JS 事实:Jon Skeet 离开了 MS,突然所有 C# 程序的运行速度比以前慢了一倍 :)
  • 您正在调用 WriteLine 添加“\n”。通过使用 StreamWriter 的构造函数重载来指定编码,它需要一个。使用 Encoding.Default 使其像 Java 版本一样工作。创建一个新的 StreamReader 而不是调用 File.OpenText - 这样您也可以在那里指定编码。
  • @kd304:我知道你这句话的主旨是个玩笑,但万一你是认真的:我从来没有为 MS 工作过。
  • @SilverHorse:是的,那肯定会快很多......但我怀疑重点不是不惜一切代价让它尽可能快,而只是找出为什么基本上Java 中的相同代码比 .NET 更快。例如,这听起来可能是 Java 在打开文件以进行追加时更快。
【解决方案2】:

我在这里没有看到任何代码问题。一些可能性:您可能在调试模式下运行了 C# 代码?文件缓存存在问题。 C# 数据文件在严重碎片化的磁盘区域上运行。对于这样一个简单的 C# 程序,我不希望有一半的速度。

编辑:我在 10439 字节的 blah.txt 上尝试了这两个版本。生成的文件长 1 043 900 字节。

C# (CTRL+F5) 时间为 18 秒
C# (F5) 时间为 22 秒
Java 时间为 17 秒。

两个应用程序占用了大约 40% 的 CPU 时间,其中一半是内核时间。

编辑2: CPU 限制是由于代码不断地打开、关闭和写入小块数据。这会导致大量托管本机和用户内核模式转换。

我的系统规格:Core 2 Duo 2.4GHz,2 GB 800MHz RAM,WinXP SP3

【讨论】:

  • 我以类似的时间在调试和发布模式下运行了 C# 代码。
  • 通过上面的评论,你的意思是你运行它已经构建它带有调试和发布,还是你在调试器中运行它而不是在调试器中?根据我的经验,后者比前者产生了很多的不同。在 Visual Studio 中,按 Ctrl-F5 而不是 F5。
  • 让我说清楚....我通过按 F5(调试)和 Ctrl+F5(不调试运行)同时运行
  • +1 用于测试 - 基本上 Java 和 C# 在不在调试器下时并驾齐驱...
【解决方案3】:

基准测试的缓慢部分看起来好像是一个文件被反复打开、修饰、小写入和再次关闭。不是一个有用的基准。明显的区别在于缓冲区有多大(一次写入,您实际上不需要任何缓冲区)以及生成的文件是否同步到磁盘。

【讨论】:

  • 你知道java和c#之间的任何简单的IO操作基准,如果我需要给大家演示的话。
  • 选择一些现实的。目前,您的瓶颈很可能是打开文件以附加到它,这通常不是实际应用程序中的瓶颈。
猜你喜欢
  • 2021-12-26
  • 2017-04-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-16
  • 2014-09-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多