【发布时间】:2019-08-29 12:52:38
【问题描述】:
关闭此线程的背面:Copy-item using invoke-async in Powershell 我有以下内容:
@mklement0 的方法(复制自 here 并由 here 修改)有效,但因为它为每个文件创建一个线程异常缓慢,并且在我的测试系统上使用约 14,000 个文件消耗 > 4GB 内存:
# This works but is INCREDIBLY SLOW because it creates a thread per file
Create sample CSV file with 10 rows.
$FileList = Join-Path ([IO.Path]::GetTempPath()) "tmp.$PID.csv"
@'
Foo,SrcFileName,DestFileName,Bar
1,c:\tmp\a,\\server\share\a,baz
2,c:\tmp\b,\\server\share\b,baz
3,c:\tmp\c,\\server\share\c,baz
4,c:\tmp\d,\\server\share\d,baz
5,c:\tmp\e,\\server\share\e,baz
6,c:\tmp\f,\\server\share\f,baz
7,c:\tmp\g,\\server\share\g,baz
8,c:\tmp\h,\\server\share\h,baz
9,c:\tmp\i,\\server\share\i,baz
10,c:\tmp\j,\\server\share\j,baz
'@ | Set-Content $FileList
# How many threads at most to run concurrently.
$NumCopyThreads = 8
Write-Host 'Creating jobs...'
$dtStart = [datetime]::UtcNow
# Import the CSV data and transform it to [pscustomobject] instances
# with only .SrcFileName and .DestFileName properties - they take
# the place of your original [fileToCopy] instances.
$jobs = Import-Csv $FileList | Select-Object SrcFileName, DestFileName |
ForEach-Object {
# Start the thread job for the file pair at hand.
Start-ThreadJob -ThrottleLimit $NumCopyThreads -ArgumentList $_ {
param($f)
[System.IO.Fileinfo]$DestinationFilePath = $f.DestFileName
[String]$DestinationDir = $DestinationFilePath.DirectoryName
if (-not (Test-path([Management.Automation.WildcardPattern]::Escape($DestinationDir)))) {
new-item -Path $DestinationDir -ItemType Directory #-Verbose
}
copy-item -path $f.srcFileName -Destination $f.destFilename
"Copied $($f.SrcFileName) to $($f.DestFileName)"
}
}
Write-Host "Waiting for $($jobs.Count) jobs to complete..."
# Synchronously wait for all jobs (threads) to finish and output their results
# *as they become available*, then remove the jobs.
# NOTE: Output will typically NOT be in input order.
Receive-Job -Job $jobs -Wait -AutoRemoveJob
Write-Host "Total time lapsed: $([datetime]::UtcNow - $dtStart)"
# Clean up the temp. file
Remove-Item $FileList
This article(特别是 PowerShell 作业部分)给了我将完整列表拆分为 1000 个文件批次的想法,当它在我的测试用例中运行时,我得到 15 个线程(因为我有大约 14,500 个文件)但线程只处理每个“块”中的第一个文件,然后停止:
<#
.SYNOPSIS
<Brief description>
For examples type:
Get-Help .\<filename>.ps1 -examples
.DESCRIPTION
Copys files from one path to another
.PARAMETER FileList
e.g. C:\path\to\list\of\files\to\copy.txt
.PARAMETER NumCopyThreads
default is 8 (but can be 100 if you want to stress the machine to maximum!)
.PARAMETER LogName
default is output.csv located in the same path as the Filelist
.EXAMPLE
to run using defaults just call this file:
.\CopyFilesToBackup
to run using anything else use this syntax:
.\CopyFilesToBackup -filelist C:\path\to\list\of\files\to\copy.txt -NumCopyThreads 20 -LogName C:\temp\backup.log -CopyMethod Runspace
.\CopyFilesToBackup -FileList .\copytest.csv -NumCopyThreads 30 -Verbose
.NOTES
#>
[CmdletBinding()]
Param(
[String] $FileList = "C:\temp\copytest.csv",
[int] $NumCopyThreads = 8,
[String] $LogName
)
$filesPerBatch = 1000
$files = Import-Csv $FileList | Select-Object SrcFileName, DestFileName
$i = 0
$j = $filesPerBatch - 1
$batch = 1
Write-Host 'Creating jobs...'
$dtStart = [datetime]::UtcNow
$jobs = while ($i -lt $files.Count) {
$fileBatch = $files[$i..$j]
$jobName = "Batch$batch"
Start-ThreadJob -Name $jobName -ThrottleLimit $NumCopyThreads -ArgumentList ($fileBatch) -ScriptBlock {
param($filesInBatch)
foreach ($f in $filesInBatch) {
[System.IO.Fileinfo]$DestinationFilePath = $f.DestFileName
[String]$DestinationDir = $DestinationFilePath.DirectoryName
if (-not (Test-path([Management.Automation.WildcardPattern]::Escape($DestinationDir)))) {
new-item -Path $DestinationDir -ItemType Directory -Verbose
}
copy-item -path $f.srcFileName -Destination $f.DestFileName -Verbose
}
}
$batch += 1
$i = $j + 1
$j += $filesPerBatch
if ($i -gt $files.Count) {$i = $files.Count}
if ($j -gt $files.Count) {$j = $files.Count}
}
Write-Host "Waiting for $($jobs.Count) jobs to complete..."
Receive-Job -Job $jobs -Wait -AutoRemoveJob
Write-Host "Total time lapsed: $([datetime]::UtcNow - $dtStart)"
我觉得我遗漏了一些明显的东西,但我不知道是什么。
谁能帮忙?
【问题讨论】:
标签: multithreading powershell copy-item