You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#与Java统计大文件中指定值字节数量的性能差异问询:为何C#慢5倍?

C#与Java统计大文件中指定值字节数量的性能差异问询:为何C#慢5倍?

最近我做了个C#和Java的性能对比测试,结果发现了一个让我困惑的情况——统计1亿字节的随机二进制文件中值大于100的字节数量时,C#的速度居然比Java慢了差不多5倍!我已经排除了调试模式的影响,甚至用BenchmarkDotNet做了严谨测试,结果还是差不多,想请教各位大佬这是怎么回事,有没有优化的方向?


测试准备:生成测试文件

首先我用Python生成了一个100,000,000字节的随机二进制文件,代码如下:

import random
import os

def Main():
    length = 100000000
    randomArray = random.randbytes(length)
    desktopPath = os.path.normpath(os.path.expanduser("~/Desktop"))
    fullPath = os.path.join(desktopPath, "RandomFile.dat")
    
    if os.path.isfile(fullPath):
        print("File already exists.")
        return
    
    with open(fullPath, "wb") as file:
        file.write(randomArray)
    print("The file has been created.")

Main()

核心测试逻辑

接下来我分别用C#和Java实现了统计逻辑,只统计TestSpeed核心函数的执行时间(文件读取和类型转换的时间不算在性能测试范围内)。

C# 实现代码

using System;
using System.Diagnostics;
using System.IO;

namespace TestYouTube
{
    public class Program
    {
        public static void Main(string[] args)
        {
            string desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
            string fullPath = Path.Combine(desktopPath, "RandomFile.dat");
            
            if (!File.Exists(fullPath))
            {
                Console.WriteLine("The file does not exist.");
                return;
            }
            
            byte[] byteArray = File.ReadAllBytes(fullPath);
            int[] intArray = ByteArrayToIntArray(byteArray);
            
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            int count = TestSpeed(intArray);
            stopwatch.Stop();
            
            Console.WriteLine($"Count = {count}");
            Console.WriteLine($"Elapsed: {stopwatch.Elapsed.TotalSeconds} seconds");
            Console.ReadLine();
        }

        private static int[] ByteArrayToIntArray(byte[] byteArray)
        {
            if (byteArray == null) return null;
            if (byteArray.Length == 0) return Array.Empty<int>();
            
            int[] intArray = new int[byteArray.Length];
            for (int i = 0; i < intArray.Length; i++)
            {
                intArray[i] = byteArray[i];
            }
            return intArray;
        }

        private static int TestSpeed(int[] array)
        {
            if (array == null) throw new ArgumentNullException();
            if (array.Length == 0) throw new ArgumentException();
            
            int count = 0;
            foreach (int element in array)
            {
                if (element > 100)
                {
                    count++;
                }
            }
            return count;
        }
    }
}

Java 实现代码

import java.io.*;
import java.nio.file.*;
import javax.swing.filechooser.FileSystemView;

public class Main {
    public static void main(String[] args) throws IOException {
        FileSystemView view = FileSystemView.getFileSystemView();
        File file = view.getHomeDirectory();
        String desktopPath = file.getPath();
        Path fullPath = Paths.get(desktopPath, "RandomFile.dat");
        File randomFile = new File(fullPath.toString());
        
        if (!randomFile.exists() || randomFile.isDirectory()) {
            System.out.println("The file does not exist.");
            return;
        }
        
        byte[] array = Files.readAllBytes(randomFile.toPath());
        int[] intArray = ByteArrayToUnsignedByteArray(array);
        
        long start = System.currentTimeMillis();
        int count = TestSpeed(intArray);
        long end = System.currentTimeMillis();
        long elapsed = end - start;
        double elapsedSeconds = ((double) elapsed) / 1000;
        
        System.out.printf("Count = %d\n", count);
        System.out.printf("Elapsed: %f seconds\n", elapsedSeconds);
    }

    private static int ByteToUnsignedByte(byte b) {
        return b & 0b11111111;
    }

    private static int[] ByteArrayToUnsignedByteArray(byte[] byteArray) {
        if (byteArray == null) return null;
        if (byteArray.length == 0) return new int[0];
        
        int[] newArray = new int[byteArray.length];
        for (int i = 0; i < byteArray.length; i++) {
            int element = ByteToUnsignedByte(byteArray[i]);
            newArray[i] = element;
        }
        return newArray;
    }

    private static int TestSpeed(int[] byteArray) {
        if (byteArray == null) throw new IllegalArgumentException("The array must not be null.");
        if (byteArray.length == 0) throw new IllegalArgumentException("The array length must be non zero.");
        
        int count = 0;
        for (int element : byteArray) {
            if (element > 100) {
                count++;
            }
        }
        return count;
    }
}

测试环境参数

  • .NET版本:.NET 9.0
  • Java版本:OpenJDK 24.0.1 2025-04-15
  • 操作系统:Windows 10 专业版 [Version 10.0.19045.5965]
  • CPU:AMD Athlon Gold 3150U with Radeon Graphics(双核Zen 1架构)

测试结果

我多次运行测试,结果非常稳定:

  • C#:用Stopwatch测试耗时约0.428秒,用BenchmarkDotNet测试的Mean值为411.2ms
  • Java:耗时约0.077秒
    两者的统计结果一致(都是60542647),但C#的速度只有Java的1/5左右。我已经确认是用Release模式+Start Without Debugging启动的C#程序,排除了调试开销的影响。

我的疑问

  1. 为什么两者的性能差异会这么大?是我的C#代码有可以优化的点,还是JIT编译器(RyuJIT vs HotSpot)的优化策略差异导致的?
  2. 有没有什么优化手段能让C#的性能追上Java?

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 10:28:09