2010-11-04 99 views
4

我在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; 
} 

我以为是非常快的(是吗?:))

的Java

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对象(很多垃圾)。在这个例子中,它并不多,但有时候我有1000万行。这引出了我的问题:

  1. c + +示例可以更快吗?
  2. 我是否应该使用StringBuilder for Java或者它也可能由于行数差而不好
  3. 还有其他方法或库吗?
  4. C#呢?

谢谢

+2

只是一个快速提示,使用''n''而不是'endl',因为'endl'强制每一行刷新数据流 – Inverse 2010-11-05 00:23:28

+0

它是否必须是文本文件?以二进制形式保存可能会显着加快速度。你在运行什么操作系统?可能有操作系统特定的功能(例如Windows中重叠的I/O)可以加快速度。 – 2010-11-05 00:52:44

+0

你必须是。我使用gnuplot,需要查看文件等。 – 2010-11-05 00:58:48

回答

5

简介它。运行代码,计时,查看需要多长时间。如果花费的时间可以接受,请使用它。如果不是的话,找出哪些部分需要花费很长时间才能运行,并对其进行优化。

  • 作出正确选择。
  • 快点。

该订单。 (有些人在这两个之前添加“让它运行/构建”)

也就是说,我之前已经在这种事情上运行过度量标准。缺点是:您正在等待磁盘,而磁盘速度很慢。不管你用C或C++还是Java编写,他们都在等待硬盘。

这里有一个previous post我在C.做了各种I/O方法,您正在寻找不完全是,但可能是提供信息。

+1

分析对于I/O绑定程序很难。 – 2010-11-04 23:13:32

+0

它总是可以接受的因为我可以在夜间运行它。我正在寻找一些提示或模式,比如当我开始用Java编程时,我使用了类似tx.println(val1 +“”+ val2 +“”+等)的东西,这有点愚蠢,并且使得我的计算变得更慢 – 2010-11-04 23:22:58

+0

@ lukas真的吗?在现代javac版本中,你有一个+ b + c的基准测试比一个StringBuilder慢吗(对于一些相当长的a,b和c)? – 2010-11-04 23:31:57

0

我希望这将是更快的C或C使用fprintf ++。

+0

特别是因为每个<< or >>是一个函数调用... – JimR 2010-11-04 23:53:26

+0

@JimR,那是我的想法。虽然简单的答案是尝试它。 – 2010-11-05 00:00:28

+0

我试过了。我建立了一个报告生成器,并且PM坚称我们使用“正确的C++功能”,C++流在这种情况下显着较慢。这是在2002年左右的地方,所以事情可能已经改变了,但是...... – JimR 2010-11-05 00:48:23

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(); 
+0

哎呀忘了添加到BY():) – 2010-11-04 23:29:05

+1

AFAIK真的没有理由使用NIO,除非需要选择器(非阻塞IO), mmap或其他“额外”功能。 “旧”Java IO API对于阻塞读/写操作来说同样快,并且多线程IO不是(总是)比选择器/ nb IO慢。 – 2010-11-04 23:50:13

+0

那总是不正确的。根据操作系统的不同,使用nio可能会更快。 http://stackoverflow.com/questions/1605332/java-nio-filechannel-versus-fileoutputstream-performance-usefulness – 2010-11-05 01:18:24

4

一个字:档案。

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

+0

+1对'endl'造成冲洗。 – Thanatos 2010-11-04 23:28:32

1

请注意,首先,根据小细节(例如,如果使用C++流或printf),此I/O绑定程序将不会得到太多改进。

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

至于Java版本,我认为它已经相当优化了。

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

0

卢卡斯,

首先,我知道主要是C#,所以这里的一切涉及到.NET。

随着你处理的行数,我不会创建字符串或使用StringBuilder。一个StringBuilder只能帮助从一些较小的段创建字符串。

我认为你最好的选择是使用Stream版本的文件系统对象。这样,你根本不存储字符串,所以你的内存使用量应该很小。另外,如果你真的对内存不够用,你总是可以创建一个非托管字符串和P/Invoke。

Erick

0

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

使用NiO和配置文件无情

2

首先,也是最重要的:使用一个缓冲的作家!

这可能包括启用某些语言在频道上的缓冲或使用BufferedWriter (in Java)或其他等效语言。如果不这样做,可能会导致性能远低于,因为输出流可能会“过度刷新” - 上面的示例代码违反了此规定(FileWriter对缓冲没有任何知识)!

在许多情况下,人们可以考虑CPU和主存储器访问“廉价”和IO“昂贵” - 在这种微不足道的情况下,改进对IO本身的访问(例如缓冲和不冲洗)导致最显着的收益。现代的虚拟机和JIT做他们做得很好的事情,短暂的对象分配/解除分配可能是这里“最担心的问题”。

相关问题