PowerShell:DownloadFileAsync的运行空间问题 [英] PowerShell: Runspace problem with DownloadFileAsync
问题描述
我需要在PowerShell 2.0中使用WebClient
下载文件,并且我想显示下载进度,所以我这样做是这样的:
I needed to download file using WebClient
in PowerShell 2.0, and I wanted to show download progress, so I did it this way:
$activity = "Downloading"
$client = New-Object System.Net.WebClient
$urlAsUri = New-Object System.Uri($url)
$event = New-Object System.Threading.ManualResetEvent($false)
$downloadProgress = [System.Net.DownloadProgressChangedEventHandler] {
$progress = [int]((100.0 * $_.BytesReceived) / $_.TotalBytesToReceive)
Write-Progress -Activity $activity -Status "${progress}% done" -PercentComplete $progress
}
$downloadComplete = [System.ComponentModel.AsyncCompletedEventHandler] {
Write-Progress -Activity $activity -Completed
$event.Set()
}
$client.add_DownloadFileCompleted($downloadComplete)
$client.add_DownloadProgressChanged($downloadProgress)
Write-Progress -Activity $activity -Status "0% done" -PercentComplete 0
$client.DownloadFileAsync($urlAsUri, $file)
$event.WaitOne()
我在$downloadProgress
处理程序中收到代码错误There is no Runspace available to run scripts in this thread.
,这是合乎逻辑的.但是,如何为(可能)属于ThreadPool
的线程提供Runspace
?
I am getting a error There is no Runspace available to run scripts in this thread.
for the code in $downloadProgress
handler, which is logical. However, how do I provide a Runspace
for the thread that (probably) belongs to the ThreadPool
?
更新: 请注意,这个问题的两个答案都是值得一读的,如果可以的话,我会接受的.
UPDATE: Note that both answers to this question are worth reading, and I would accept both if I could.
推荐答案
感谢stej的点头.
Thanks stej for the nod.
Andrey,powershell有其自己的线程池,并且每个服务线程都保留一个指向运行空间的线程静态指针(System.Management.Automation.Runspaces.Runspace.DefaultRunspace静态成员公开了该静态指针,并且在您的回调中为空引用.)最终,这意味着很难(尤其是在脚本中)使用自己的线程池(由.NET为异步方法提供)来执行脚本块.
Andrey, powershell has its own threadpool and each service thread keeps a threadstatic pointer to a runspace (the System.Management.Automation.Runspaces.Runspace.DefaultRunspace static member exposes this - and would be a null ref in your callbacks.) Ultimately this means it's difficult - especially in script - to use your own threadpool (as is provided by .NET for async methods) to execute scriptblocks.
PowerShell 2.0
无论如何,由于powershell v2完全支持事件处理,因此无需使用此功能:
Regardless, there is no need to play with this as powershell v2 has full support for eventing:
$client = New-Object System.Net.WebClient
$url = [uri]"http://download.microsoft.com/download/6/2/F/" +
"62F70029-A592-4158-BB51-E102812CBD4F/IE9-Windows7-x64-enu.exe"
try {
Register-ObjectEvent $client DownloadProgressChanged -action {
Write-Progress -Activity "Downloading" -Status `
("{0} of {1}" -f $eventargs.BytesReceived, $eventargs.TotalBytesToReceive) `
-PercentComplete $eventargs.ProgressPercentage
}
Register-ObjectEvent $client DownloadFileCompleted -SourceIdentifier Finished
$file = "c:\temp\ie9-beta.exe"
$client.DownloadFileAsync($url, $file)
# optionally wait, but you can break out and it will still write progress
Wait-Event -SourceIdentifier Finished
} finally {
$client.dispose()
}
PowerShell v1.0
If you're stuck on v1 (this is not specifically for you as you mention v2 in the question) you can use my powershell 1.0 eventing snap-in at http://pseventing.codeplex.com/
异步回调
.NET中另一个棘手的地方是异步回调.在Powershell的v1或v2中没有直接帮助您的东西,但是您可以使用一些简单的管道将异步回调转换为事件,然后使用常规事件处理该事件.我在 http://poshcode.org/1382
Another tricky area in .NET is async callbacks. There is nothing directly in v1 or v2 of powershell that can help you here, but you can convert an async callback to an event with some simple plumbing and then deal with that event using regular eventing. I posted a script for this (New-ScriptBlockCallback) at http://poshcode.org/1382
希望这会有所帮助,
-Oisin
这篇关于PowerShell:DownloadFileAsync的运行空间问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!