PromptPlus icon indicating copy to clipboard operation
PromptPlus copied to clipboard

PromptPlus output becomes messy from inside Parallel.ForEach or Parallel.Invoke functions

Open ividyon opened this issue 2 years ago • 4 comments

Tested with simple WriteLine.

From inside Parallel:

2024-01-13_12-01-33__WindowsTerminal

Without Parallel:

2024-01-13_12-07-45__WindowsTerminal

ividyon avatar Jan 13 '24 11:01 ividyon

Hello ivideon, This behavior does not depend on the implementation of Prompt Plus but on the concept of parallelism functions that do not guarantee the execution sequence. Once prompplus knows what it will write to the console (stream out) it sends it to the default provider which "prints" the result. As the "print" does not have a guarantee of sequence due to parallelism, the result is confusing.

In other words, console operations do not work well with multi-threads unless the application itself manages the result and organizes the data before sending it to the console.

Try this and see the result (it will be confusing too)

        static void Main(string[] args)
        {
            Console.Clear();
            Console.WriteLine("write 100 line Without Parallel:");
            for (int i = 0; i < 100; i++) 
            {
                Console.Write("test Console.Write ");
                Console.WriteLine($"value is {i} ");

            }
            Console.WriteLine("Press Any Key");
            Console.ReadKey(false);
            Console.Clear();
            Console.WriteLine("write 100 line From inside Parallel.for:");
            Parallel.For(1,100,(i) =>
            {
                Console.Write("test Console.Write ");
                Console.WriteLine($"value is {i} ");
            });
        }

FRACerqueira avatar Jan 15 '24 21:01 FRACerqueira

Looks like this can be improved with the following:

internal static class Program
{
    internal static object ConsoleWriterLock = new object();

    static void Main(string[] args)
    {
        Console.Clear();
        Console.WriteLine("write 100 line Without Parallel:");
        for (int i = 0; i < 100; i++)
        {
            Console.Write("test Console.Write ");
            Console.WriteLine($"value is {i} ");
        }

        Console.WriteLine("Press Any Key");
        Console.ReadKey(false);
        Console.Clear();

        Console.WriteLine("write 100 line From inside Parallel.for:");
        Parallel.For(1, 100, (i) =>
        {
            lock (ConsoleWriterLock)
            {
                Console.Write("test Console.Write ");
                Console.WriteLine($"value is {i} ");
            }
        });
    }
}

Before: 2024-01-16_07-52-29__rider64

After: 2024-01-16_07-52-53__rider64

Using lock() {} with a static readonly object makes the output orderly during parallel processing, at (assumably) the cost of a bit of parallel performance (but we're probably talking microseconds here).

Some kind of PromptPlus.LockOutput boolean which enables such behavior, as well as access to a public PromptPlus.ConsoleLock object which is used for this (for making their own custom locks) could be great and save users the effort of wrapping each of their own Writes.

ividyon avatar Jan 16 '24 06:01 ividyon

Pressed the wrong button...

ividyon avatar Jan 16 '24 06:01 ividyon

I'll also note that this issue doesn't occur if you do .Write("MyString" + "\n") instead of WriteLine

ividyon avatar Mar 04 '24 06:03 ividyon