Slow updates to my event handler from DownloadFileAsync during DownloadProgressChanged event

陌路散爱 提交于 2019-12-05 15:41:38
latkin

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 events
Add-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 }
 }
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!