-1

I have a parallel loop in a console application with a StopWatch.

If I input 10000 loops it says it finishes in 13 seconds but in real world the console doesn't stop printing until 15 minutes later. So how can I properly time this loop so the stopwatch stops after the last line has finished writing to the console? My expected result is "Process took 903 Seconds"

int i = 0;
int N = 10000;
Stopwatch sw = new StopWatch();
sw.Start
    Parallel.For(0, N, i =>
            {
                //Do some logic task here then write to the console
                console.Writeline("Thread " + i + " has finished");
            });

sw.Stop()
console.WriteLine("Process took" + sw.Elapsed.Seconds + " Seconds");

Is is similar to C# Timespan Milliseconds vs TotalMilliseconds where one used Milliseconds instead of TotalMilliseconds?

Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
CodeMan03
  • 570
  • 3
  • 18
  • 43
  • I'm just trying to figure out how you parallelize writing to `Console` – JohanP Jan 13 '21 at 05:22
  • I bet this is "when I start multiple tasks in `Parallel.For` they are started quite quickly" type of question... Which is "clearly" seen from "some logic task" comment. Surprising that it has no close votes for missing [MRE].... – Alexei Levenkov Jan 13 '21 at 05:36
  • I think what you are noticing is that writing to the console is not an atomic operation. Meaning, writing 10000 lines to the console techincally takes x numbers of seconds, but takes more time to actually display – TheGeneral Jan 13 '21 at 05:38
  • 2
    @00110001 AFAIK writing to the console is a synchronous/blocking operation. My expectation is that the actual and the measured time of writing 10000 lines would be the same. – Theodor Zoulias Jan 13 '21 at 05:42
  • 1
    CodeMan03 could you edit the question, and include the code that is currently represented by the comment `//Do some logic task here then write to the console`? – Theodor Zoulias Jan 13 '21 at 05:44
  • Slightly unrelated: Stopwatch _is not_ a Benchmarking tool. For a rough quick estimate, it may be sufficient, but if you really want to thoroughly benchmark some code, consider BenchmarkDotNet (not affiliated). – Fildor Jan 13 '21 at 07:50

2 Answers2

6

From the documentation of the TimeSpan.Seconds property:

public int Seconds { get; }

Gets the seconds component of the time interval represented by the current TimeSpan structure.

So the Seconds return a value between 0 - 59. To get the total duration of the TimeSpan in seconds you need to query the TimeSpan.TotalSeconds property:

public double TotalSeconds { get; }

Gets the value of the current TimeSpan structure expressed in whole and fractional seconds.

Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
  • 1
    hahah, wow i was totally wrong plus one (this is why one should not answer questions at 4pm while at work) – TheGeneral Jan 13 '21 at 06:02
  • 1
    @00110001 I have a feeling that this answer will bring me some easy rep points. – Theodor Zoulias Jan 13 '21 at 06:04
  • 1
    I've edited question to match your answer... I don't believe code shown by OP actually can take 15minutes, so I think it is fine to just scope down the question to "Why seconds don't return total seconds". – Alexei Levenkov Jan 13 '21 at 06:57
1

You need to use sw.Elapsed.TotalSeconds which returns a double instead of .Seconds which returns the integer seconds part of (hours,minutes,seconds,..)

The rest of the code is correct.

example code:

static class Program
{
    static void Main(string[] args)
    {
        int N = 10000;
        Stopwatch sw = new Stopwatch();
        sw.Start();
        Parallel.For(0, N, (i) =>
        {
            //Do some logic task here then write to the console
            LongTask();
            Console.WriteLine($"Iteration {i} has finished in thread {Thread.CurrentThread.ManagedThreadId}");
        });
        sw.Stop();
        Console.WriteLine($"Process took {sw.Elapsed.TotalSeconds} Seconds");
    }

    static double LongTask()
    {
        double x = 1;
        for (int i = 1; i <= 2<<55; i++)
        {
            x += Math.Pow(1+1/i,i);
        }
        return x;
    }
}

NOTE: Always run timing on Release builds, and if run from VS, use the Start without Debugging command.

pic2

John Alexiou
  • 28,472
  • 11
  • 77
  • 133
  • Alternatively you could use the [Stopwatch.ElapsedMilliseconds](https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.stopwatch.elapsedmilliseconds) property. This is what I personally prefer. – Theodor Zoulias Jan 13 '21 at 06:49
  • @TheodorZoulias The question being does `Elapsed.TotalSeconds` offer sub-millisecond resolution and thus an advantage of `.ElapsedMilliseconds`? – John Alexiou Jan 13 '21 at 13:14
  • AFAIK yes. Personally I don't need finer resolution to milliseconds, but if I am not mistaken the `Stopwatch` provides resolution close to hundreds of nanoseconds or something. – Theodor Zoulias Jan 13 '21 at 15:31