Slow updates to my event handler from DownloadFileAsync during DownloadProgressChanged event Slow updates to my event handler from DownloadFileAsync during DownloadProgressChanged event powershell powershell

Slow updates to my event handler from DownloadFileAsync during DownloadProgressChanged event


Async eventing is rather poorly supported in Powershell. When events are fired they go into some Powershell event queue, which is then fed to handlers as they become available. I've seen various performance or functionality issues with this before, where it seems the handlers need to wait for the console to become idle before they are executed. See this question for an example.

From what I can tell, your code is set up well and "should" work. I think it's slow just because powershell doesn't support this kind of pattern very well.

Here's a workaround which reverts to plain .NET C# code to handle all the event stuff, which avoids the Powershell event queue entirely.

# helper for handling eventsAdd-Type -TypeDef @"  using System;  using System.Text;  using System.Net;  using System.IO;  public class Downloader  {      private Uri source;      private string destination;      private string log;      private object syncRoot = new object();      private int percent = 0;      public Downloader(string source, string destination, string log)      {          this.source = new Uri(source);          this.destination = destination;          this.log = log;      }      public void Download()      {          WebClient wc = new WebClient();          wc.DownloadProgressChanged += new DownloadProgressChangedEventHandler(OnProgressChanged);          wc.DownloadFileAsync(source, destination);      }      private void OnProgressChanged(object sender, DownloadProgressChangedEventArgs e)      {          lock (this.syncRoot)          {              if (e.ProgressPercentage > this.percent)              {                  this.percent = e.ProgressPercentage;                  string message = String.Format("{0}: {1} percent", DateTime.Now, this.percent);                  File.AppendAllLines(this.log, new string[1] { message }, Encoding.ASCII);              }          }      }  }"@$source = 'https://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.18.tar.bz2'$dest = "$env:USERPROFILE\Downloads\linux-2.6.18.tar.bz2"$log = [io.path]::GetTempFileName()$downloader = new-object Downloader $source,$dest,$log$downloader.Download();gc $log -tail 1 -wait ` |?{ $_ -match ': (\d+) percent' } ` |%{      $percent = [int]$matches[1]     if($percent -lt 100)     {         Write-Progress -Activity "Downloading $source" -Status "${percent}% complete" -PercentComplete $percent     }     else{ break } }