tech.guitarrapc.cóm

C#, PowerShell, Unity, Cloud, Serverless Technical Update and Features

PowerShellでSystem.Net.WebClient.DownloadFileAsync利用時の注意点(備忘録)

昨夜、勉強になったので備忘録に。 PowerShellではしょっちゅう.NETを利用します。 その中でも、System.Net.WebClientは、サイトのHTMLを取得する際に便利なので利用しがちです。 DownloadFileとDownloadFileAsyncの利用時の違いがイマイチピンときて無かったのが少し解消したので備忘録に。

DownloadFile利用例

まずは利用例から。
$URI = "http://example.net/"
$savefile = "D:\example\exmaple"
$ext = ".html"

$syncWebClient = New-Object -TypeName System.Net.WebClient
10001..20000 | %{
    $syncWebClient.DownloadFile($URI,$($savefile + $_ + $ext))
}
.NETライクで、パイプを噛ませてないので寂しいのですが。 これで、10000回、対象サイトのHTMLを取得して、自身のD:\exampleにダウンロード、ファイル名に何回目のファイルかをつけてくれます。 $()は部分式ですが、良く使いますね。 DownloadFileは、同期方式です。 同期の場合は、System.Net.WebClientで一つずつの処理を終わるまで次のDownloadFileメソッドを実行しないので生成は一回でいいとなります。

DownloadFileAsync利用例

まずは利用例から。
$URI = "http://example.net/"
$savefile = "D:\example\exmaple"
$ext = ".html"

1..10000 | %{
    $asyncWebClient = New-Object -TypeName System.Net.WebClient
    $asyncWebClient.DownloadFileAsync($URI,$($savefile + $_ + $ext))
}
先ほどとの違いは、New-ObjectでのSystem.Net.WebClientインスタンス生成が都度行われている点です。 これは、DownloadAsyncが実行後すぐにComplete扱いになるため、接続分のインスタンスを生成する必要があります。 仮に、DownlaodFileと同様に以下のように書くと、
$URI = "http://example.net/"
$savefile = "D:\example\exmaple"
$ext = ".html"

$asyncWebClient = New-Object -TypeName System.Net.WebClient
1..10000 | %{
    $asyncWebClient.DownloadFileAsync($URI,$($savefile + $_ + $ext))
}
非同期の場合は、System.Net.WebClientを随時生成しないと以下のエラーが2つめのダウンロード以降出てきます。
"2" 個の引数を指定して "DownloadFileAsync" を呼び出し中に例外が発生しました: "WebClient は同時 I/O 操作をサポートしません。"

実行速度

それはもう、DownloadFileAsyncの方が早いです。 DownloadFileAsyncなら、必要数のインスタンス生成分だけの時間だけロック。ダウンロードは非同期に。 DownlaodFileだと、インスタンスの生成は一個ですが、ファイルダウンロード中ロックされます。 結果は、一目瞭然ですね。 DownloadFileAsyncの場合、現在ダウンロード中かどうかの判断は……単純にこれでいいか…。
CancelAsync メソッドを使用すると、未完了の非同期操作をキャンセルできます。