Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parallel.ForEach Pretty Logging Impossible?

I'm thinking it's impossible to have a pretty log when using Parallel.ForEach. Unless someone has a few tricks they can show me?

namespace Parallel_ForEach_Logging
{
    class Program
    {
        private static uint _callCount = 0;

        static void Main(string[] args)
        {
            IEnumerable<int> data = Enumerable.Range(0, 2);

            Console.Out.WriteLine("***");

            ParallelOptions options = new();
            options.MaxDegreeOfParallelism = Environment.ProcessorCount;

            Parallel.ForEach(data, options, datum =>
            {
                PrintNum(datum, _callCount++);
            });

            Console.Out.Flush();
            Console.Out.WriteLine("***");
        }

        public static void PrintNum(int num, uint callCount)
        {
            Console.Out.WriteLine($">>> IN {callCount}");
            // Console.Out.WriteLine($"  {num}");
            Console.Out.WriteLine($"<<< OUT {callCount}");
            PrintString($"\"{num.ToString()}\"", callCount);
        }

        public static void PrintString(string str, uint callCount)
        {
            Console.Out.WriteLine($">>> IN {callCount}");
            // Console.Out.WriteLine($"  {str}");
            Console.Out.WriteLine($"<<< OUT {callCount}");
        }
    }
}

Here is what I think of when I say pretty log:

>>> IN: Method A
  >>> IN : Method 1 called.
  <<< OUT: Method 1 done.
  >>> IN : Method 2 called.
  <<< OUT: Method 2 done.
<<< OUT: Method A done in 32 milliseconds.
>>> IN: Method B
...

Here is a sample log that I'm currently getting:

>>> IN 1
>>> IN 0
<<< OUT 0
<<< OUT 1
>>> IN 0
<<< OUT 0
>>> IN 1
<<< OUT 1

Notice at the top there are two IN's back-to-back and then two OUT's back-to-back.

In the code _callCount is my attempt at figuring a call depth to use for indentation but I don't see how to make this work. Even if I did, I'm not sure I could do it without a million spaces in each log entry.

I know if I took the Parallel.ForEach out of the equation I could make this work for sure.

I'm okay if this truly is impossible to accomplish. I just need someone who is way smarter than me to say so. ;)


1 Answers

Use a StringBuilder as a buffer. Add it as a parameter to your printing functions, like this:

public static void PrintNum(StringBuilder builder, int num, uint callCount)
{
    builder.Append($">>> IN {callCount}\r\n");
    builder.Append($"<<< OUT {callCount}\r\n");
    PrintString(builder, $"\"{num.ToString()}\"", callCount);
}

public static void PrintString(StringBuilder builder, string str, uint callCount)
{
    builder.Append($">>> IN {callCount}\r\n");
    builder.Append($"<<< OUT {callCount}\r\n");
}

Now you can do this:

Parallel.ForEach(data, options, datum =>
{
    var builder = new StringBuilder();
    PrintNum(builder, datum, _callCount++);
    Console.Out.WriteLine(builder.ToString());
});
like image 130
John Wu Avatar answered Jun 16 '26 18:06

John Wu



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!