C # async / awaiting progress report not in expected order

I am experimenting with async / wait and progress reports and therefore wrote a method for copying an asynchronous file that reports progress after each MB copied:

public async Task CopyFileAsync(string sourceFile, string destFile, CancellationToken ct, IProgress<int> progress) {

  var bufferSize = 1024*1024 ;
  byte[] bytes = new byte[bufferSize];
  using(var source = new FileStream(sourceFile, FileMode.Open, FileAccess.Read)){
    using(var dest = new FileStream(destFile, FileMode.Create, FileAccess.Write)){

      var totalBytes = source.Length;
      var copiedBytes = 0;
      var bytesRead = -1;
      while ((bytesRead = await source.ReadAsync(bytes, 0, bufferSize, ct)) > 0)
      {
        await dest.WriteAsync(bytes, 0, bytesRead, ct);
        copiedBytes += bytesRead;
        progress?.Report((int)(copiedBytes * 100 / totalBytes));
      }
    }
  }
}

In a console application, create an i file with a random content of 10 MB, and then copy it using the method above:

private void MainProgram(string[] args)
{
  Console.WriteLine("Create File...");
  var dir = Path.GetDirectoryName(typeof(MainClass).Assembly.Location);
  var file = Path.Combine(dir, "file.txt");
  var dest = Path.Combine(dir, "fileCopy.txt");

  var rnd = new Random();
  const string chars = ("ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890");
  var str = new string(Enumerable
                       .Range(0, 1024*1024*10)
                       .Select(i => letters[rnd.Next(chars.Length -1)])
                       .ToArray());
  File.WriteAllText(file, str);

  var source = new CancellationTokenSource();
  var token = source.Token;

  var progress = new Progress<int>();
  progress.ProgressChanged += (sender, percent) => Console.WriteLine($"Progress: {percent}%");

  var task = CopyFileAsync(file, dest, token, progress);
  Console.WriteLine("Start Copy...");
  Console.ReadLine();
}

After the application runs, both files are identical, so the copy process is performed in the correct order. However, the console output looks something like this:

Create File...
Start Copy...
Progress: 10%
Progress: 30%
Progress: 20%
Progress: 60%
Progress: 50%
Progress: 70%
Progress: 80%
Progress: 40%
Progress: 90%
Progress: 100%

The order changes every time I call the application. I do not understand this behavior. If I set a breakpoint for the event handler and check each value, they will be in the correct order. Can someone explain this to me?

, .

+4
1

Progress<T> SynchronizationContext . SynchronizationContext (, ) - . , , , , .

:

  • WPF: Dispatcher.BeginInvoke()

  • WinForms: Control.BeginInvoke

WinForms, WPF BeginInvoke ( )

+2

Source: https://habr.com/ru/post/1690169/


All Articles