spectre.console icon indicating copy to clipboard operation
spectre.console copied to clipboard

StartAsync can block

Open kuhnboy opened this issue 3 years ago • 1 comments

Information

  • OS: Windows
  • Version: 0.43.0
  • Terminal: Windows Terminal

Describe the bug When starting a progress task with StartAsync, I would expect a new task to be created inside of StartAsync via TaskFactory.StartNew in order for it to be non-blocking when synchronous code is inside of the StartAsync action. Currently in the example, the 'otherTask' line is not hit until the progress is completed.

var progressTask = AnsiConsole.Progress()
    .StartAsync(async ctx =>
    {
        // Define tasks
        var task1 = ctx.AddTask("[green]Reticulating splines[/]");
        var task2 = ctx.AddTask("[green]Folding space[/]");

        while (!ctx.IsFinished)
        {
            // Simulate a synchronous operation like a database driver that may not have asynchronous I/O.
            Thread.Sleep(5000);

            // Increment
            task1.Increment(1.5);
            task2.Increment(0.5);
        }
    });

var otherTask = Task.StartNew(() => doStuff());

Task.WaitAll(progressTask, otherTask).

To Reproduce Shown Above. Workarounds are wraping AnsiConsole.Progress in a TaskFactory.StartNew or have await Task.Yield() inside of the action of StartAsync.

Expected behavior StartAsync would be non-blocking even if there are blocking things inside of StartAsync's action.

kuhnboy avatar Jan 05 '22 16:01 kuhnboy

If you run AnsiConsole.Progress().StartAsync() then action parameter should contain await operations to use async feature. I think that using only sunchronous operations inside StartAsync require to use Task.Run and it's correct solution. Your sample should look more like this:

var progressTask = AnsiConsole.Progress()
    .StartAsync( async ctx =>
    {
        var task1 = ctx.AddTask( "[green]Reticulating splines[/]" );
        while ( !ctx.IsFinished )
        {
            await Task.Delay( 1000 );
            task1.Increment( 50 );
            AnsiConsole.WriteLine( task1.Value );
        }
    } );
var otherTask = Task.Run( () => AnsiConsole.WriteLine( "Other stuff" ) );
await Task.WhenAll( progressTask, otherTask );
AnsiConsole.WriteLine( "Done" );

Then you will see in the output

Other stuff
50
100

danielklecha avatar Feb 11 '22 06:02 danielklecha

Has @danielklecha's comment above fixed this issue for you @kuhnboy?

FrankRay78 avatar Mar 07 '24 09:03 FrankRay78