Home

Cannot update multiple progressbars asynchronously

This works well:
Enumerable
  .Range(0, 10)
  .ToList()
  .ForEach(x =>
  {
    var progressBar = new Util.ProgressBar().Dump();

    for (var i = 0; i <= 64; i++)
    {
      Thread.Sleep(10);
      progressBar.Fraction = (double)i / 64.0;
    }
  });
I see 10 progressbars updating sequentially from 0% to 100% (OK).

This doesn't work well:
ParallelEnumerable
  .Range(0, 10)
  .ForAll(x =>
  {
    var progressBar = new Util.ProgressBar().Dump();

    for (var i = 0; i <= 64; i++)
    {
      Thread.Sleep(10);
      progressBar.Fraction = (double)i / 64.0;
    }
  });
I'd expect to see 10 progress bars updating simultaneously, however I only see one progressbar updating from 0% to 100% (NOK).

Simpler examples:
var pb1 = new Util.ProgressBar().Dump();
var pb2 = new Util.ProgressBar().Dump();
pb2.Fraction = 1;
Result: Two progress bars are visible, one 0% and one 100% (OK)
var pb1 = new Util.ProgressBar().Dump();
pb1.Fraction = 1;
var pb2 = new Util.ProgressBar().Dump();
Result: One progress bar is visible at 100% (NOK)

What makes the output a bit uncertain, after applying .Sleep() it is correct:
var pb1 = new Util.ProgressBar().Dump();
pb1.Fraction = 1;
Thread.Sleep(100);
var pb2 = new Util.ProgressBar().Dump();
pb2.Fraction = .5;
Result: Two progress bars are visible, one at 100% and one at 50% (OK).

Comments

  • I'll look into the problem soon; in the meantime, you can work around this by specifying a title when calling Util.ProgressBar.

    Also bear in mind that ParallelEnumerable is not designed for I/O-bound work and you might not get the desired level of concurrency. Try this instead:
    for (int i = 0; i < 10; i++)
    {
        var progressBar = new Util.ProgressBar (i.ToString()).Dump();
        Task.Run (async () =>
        {
            for (var j = 0; j <= 64; j++)
            {
                await Task.Delay (10);
                progressBar.Fraction = (double)j / 64.0;
            }
        });
    }
    Or with Reactive Extensions:
    
    for (int i = 0; i < 10; i++)
    {
        var progressBar = new Util.ProgressBar (i.ToString()).Dump();
        
        Observable.Interval (TimeSpan.FromMilliseconds (10))
            .Take(64)
            .Subscribe (x => progressBar.Fraction = (double)x / 64.0);
    }
  • Setting the caption is an instant fix; your other remark will probably explain why I got critical I/O errors in my event log when running several BinaryWriters at the same time. Will take another look. Thank you very much!
Sign In or Register to comment.