Jon Skeet [C# MVP] <> wrote:
> > Cygwin offers easy way to time with time command. If you can time all
> > the becnhmarks as easily on Windows and get different results, let us
> > know.
>
> What I *will* do is amend the sumcol test to be sensible in the first
> place - to run *once* with a suitably large input. That way you can
> easily measure the time taken within the app, discounting the
> (massively repeated) startup costs.
Okay, done - and it's interesting.
First here's a program to duplicate the original input file:
using System.IO;
class DuplicateSumCol
{
static void Main(string[] args)
{
string text = File.ReadAllText("sumcol-input.txt");
int iterations = int.Parse(args[0]);
File.Delete("sumcol-large.txt");
for (int i=0; i < iterations; i++)
{
File.AppendAllText("sumcol-large.txt", text);
}
}
}
I ran that with an input parameter of 10000 to get a 43MB file, which
appears to be large enough to give interesting results.
Then I refactored both the Java and C# versions to allow input either
from a file or from standard input. The bulk of the time is spent in a
single method, so it shouldn't make much difference - and if *either*
language is significantly hampered by this sort of refactoring, then
frankly it deserves all it gets. Here's the C# version:
using System;
using System.Diagnostics;
using System.IO;
class SumCol
{
static void Main(string[] args)
{
int sum;
Stopwatch sw = Stopwatch.StartNew();
if (args.Length == 0)
{
sum = Parse(Console.In);
}
else
{
using (TextReader reader = File.OpenText(args[0]))
{
sum = Parse(reader);
}
}
long elapsed = sw.ElapsedMilliseconds;
Console.WriteLine("Result: {0}", sum);
Console.WriteLine("Elapsed millis: {0}", elapsed);
}
static int Parse (TextReader reader)
{
int sum = 0;
string line;
while ( (line=reader.ReadLine()) != null)
{
sum += int.Parse(line);
}
return sum;
}
}
And here's the Java version:
import java.io.*;
public class SumCol
{
public static void main(String[] args) throws Exception
{
int sum;
long start = System.currentTimeMillis();
if (args.length==0)
{
sum = parse(System.in);
}
else
{
// For the sake of brevity, don't bother closing...
sum = parse(new BufferedInputStream
(new FileInputStream(args[0])));
}
long end = System.currentTimeMillis();
System.out.println("Result: " + sum);
System.out.println("Elapsed millis: " + (end-start));
}
static int parse(InputStream stream) throws IOException
{
int sum = 0;
StreamTokenizer lineTokenizer = new StreamTokenizer(stream);
while (lineTokenizer.nextToken() != StreamTokenizer.TT_EOF)
{
sum += (int) lineTokenizer.nval;
}
return sum;
}
}
I'm running .NET 3.5, and here's all the Java information:
java version "1.6.0_05"
Java(TM) SE Runtime Environment (build 1.6.0_05-b13)
Java HotSpot(TM) Client VM (build 10.0-b19, mixed mode, sharing)
The C# version was compiled with:
csc -o+ -debug- SumCol.cs
The Java version was compiled with:
javac SumCol.java
I'm running on an Intel Core 2 Duo with 32-bit Vista.
Results (in ms):
SumCol.exe < sumcol-large.txt: 4833
SumCol.exe sumcol-large.txt: 3327
java SumCol < sumcol-large.txt: 3321
java SumCol sumcol-large.txt: 3315
Feel free to suggest changes to how the Java version is run, of course
- and please test on your own machine.
My conclusion: Java and .NET are effectively neck and neck here in
terms of actual *processing*, but .NET's console handling slows it down
significantly. No great loss IMO - I very rarely pipe large input from
the console.
--
Jon Skeet - <>
Web site:
http://www.pobox.com/~skeet
Blog:
http://www.msmvps.com/jon.skeet
C# in Depth:
http://csharpindepth.com