5

我用 Java、C# 和 C++ 进行了一些数值计算。其中一些保存了大量数据(到文本文件)。最快的方法是什么?

C++

ofstream file;
file.open(plik);
for(int i=0;i<251;i++){
    for(int j=0;j<81;j++)
        file<<(i-100)*0.01<<" "<<(j-40)*0.01<<" "<<U[i][j]<<endl;
    file<<endl;
}

我认为这非常快(我是对的吗?:))

爪哇

void SaveOutput(double[][] U, String fileName) throws IOException
{
    PrintWriter tx = new PrintWriter(new FileWriter(fileName));
    for(int i=0;i<251;i++)
    {
        for(int j=0;j<81;j++)
        {
            tx.println(String.format("%e %e %e ",(i - 100) * dz, (j - 40) * dz, U[i][j]));
        }
        tx.println();
    }
    tx.close();
}

C# 示例类似。

这就是困扰我的地方。我为每一行创建一个 String 对象(很多垃圾)。在这个例子中,它并不多,但有时我有 10 000 000 行。这引出了我的问题:

  1. c++示例可以更快吗?
  2. 我应该为 Java 使用 StringBuilder 还是由于行数的原因它也很糟糕
  3. 还有其他方法或库吗?
  4. C# 呢?

谢谢

4

8 回答 8

5

剖析它。运行代码,计时,看看需要多长时间。如果花费的时间可以接受,请使用它。如果没有,请找出需要很长时间才能运行的部分,并对其进行优化。

  • 改正它。
  • 快一点。

那个命令。(有些人在这两个之前添加“让它运行/构建”......)

也就是说,我之前实际上已经在这类事情上运行过指标。简而言之:您正在等待磁盘,而磁盘速度非常慢。不管你是用 C 还是 C++ 或 Java 编写,它们都在等待硬盘。

这是我在 C 中的各种 I/O 方法上所做的前一篇文章。不完全是您正在寻找的内容,但可能会提供信息。

于 2010-11-04T23:08:42.620 回答
4

一个字:简介。

请注意,插入std::endl缓冲(文件)流会导致它刷新,这可能会降低性能(从语言 POV 来看,这意味着缓冲区被“写出”,尽管这可能不一定意味着物理磁盘访问)。对于简单地打印换行符,请使用'\n'- 它永远不会更糟。

于 2010-11-04T23:10:48.423 回答
2

首先,也是最重要的:使用缓冲写入器!

这可能包括在某些语言中启用通道缓冲或在其他语言中使用BufferedWriter(在 Java 中)或等效项。不这样做可能会导致性能低得多,因为输出流可能“过度刷新”——上面的示例代码违反了这一点(FileWriter 对缓冲一无所知)!

在许多情况下,人们可以认为 CPU 和主内存访问“便宜”而 IO 访问“昂贵”——在这种微不足道的情况下,改进对 IO 本身的访问(例如缓冲而不是 [过度] 刷新)将导致最实实在在的收获。现代 VM 和 JIT 做得很好,短期对象分配/取消分配可能是这里最不“担心”的问题。

于 2010-11-04T23:24:45.307 回答
1

改用 Java.nio 类创建通道。通道对 java 来说是新的,并且比旧的流快得多。您还应该缓冲写入。我不记得默认情况下通道是否缓冲。我需要读一些来告诉你。

最后,你可以创建很多字符串。你会立即把它们扔掉。我怀疑它会使您写入磁盘的速度变慢。磁盘 IO 比 CPU 慢得多。

这是我的想法:

fileChannel = new FileOutputStream("test.txt").getChannel();
for(int i=0;i<251;i++) {
  for(int j=0;j<81;j++) {
    fileChannel.write(ByteBuffer.wrap((String.format("%e %e %e ",(i - 100) * dz, (j - 40) * dz, U[i][j]) + "\n").toBytes());
  }
fileChannel.close();
于 2010-11-04T23:08:46.400 回答
1

首先请注意,这个 I/O 绑定程序不会因为小细节而得到太大改进(例如,如果您使用 C++ 流或printf)。

对于 C/C++ 部分,有人说使用 ol'printf操作更快。它可能更快,但不是那个数量级,所以我不会打扰。

至于Java版本,我觉得已经相当优化了。

不能告诉 C#,我的医生不允许我 :)

于 2010-11-04T23:11:41.577 回答
0

fprintf我希望在 C 或 C++中使用它会更快。

于 2010-11-04T23:08:12.480 回答
0

卢卡斯,

首先,我主要了解 C#,所以这里的一切都与 .NET 有关。

由于您正在处理的行数,我不会创建字符串或使用 StringBuilder。StringBuilder 仅有助于从许多较小的段创建字符串。

我认为您最好的选择是使用文件系统对象的 Stream 版本。这样,您根本不会存储字符串,因此您的内存使用量应该相当小。

此外,如果您真的内存不足,您总是可以创建一个非托管字符串并将 P/Invoke 放入其中。

埃里克

于 2010-11-04T23:12:51.733 回答
0

至于 Java,您不必创建所有这些字符串。摆脱String.format并直接写入字节。

无情使用nio和profile

于 2010-11-04T23:13:04.383 回答