2

虽然这可能是重复的,但这是不同的。

我已经编写了一个脚本来使用 PowerShell 快速删除包含大量文件和子文件夹的文件夹,现在我将发布我是如何实现并行处理的,并设置一些示例:

功能:

function Parallel-Delete {
    param(
    [Parameter(Valuefrompipeline=$true, Mandatory=$true, Position=0)] [array]$filelist,
    [Parameter(Valuefrompipeline=$true, Mandatory=$true, Position=1)] [int]$number
    )
    0..($filelist.count-1) | Where-Object {$_ % 16 -eq $number} | foreach {Remove-Item -Path $filelist[$_]}
}

制作一个测试文件夹并列出内容:

$test=[string]"C:\test"+$(get-random)
md $test | out-null
0..10000 | % {ni "${test}\${_}.txt"}|out-null
[array]$filelist=(Get-Childitem -Path $test -File -Force).Fullname

测试1:

0..15 | foreach-object {Invoke-Command -ScriptBlock { Parallel-Delete $filelist $_}}
rd $test

我已经确认并行进程正在工作,但并行进程使用与单线程进程相同数量的资源:

Test2(在运行新测试之前重新制作测试文件夹):

(Get-Childitem -Path $test -File -Force).Fullname | Foreach {Remove-Item -Path $_}
rd $test

而16个并行进程的删除速度并没有想象中单线程进程的16倍,结果如下:

测试1:

PS C:\Windows\System32>Measure-Command {0..15 | foreach-object {Invoke-Command -ScriptBlock { Parallel-Delete $filelist $_}}}

Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 36
Milliseconds      : 279
Ticks             : 362798015
TotalDays         : 0.000419905109953704
TotalHours        : 0.0100777226388889
TotalMinutes      : 0.604663358333333
TotalSeconds      : 36.2798015
TotalMilliseconds : 36279.8015

测试2:

PS C:\Windows\System32>Measure-Command {(Get-Childitem -Path $test -File -Force).Fullname | Foreach {Remove-Item -Path $_}}

Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 25
Milliseconds      : 980
Ticks             : 259802514
TotalDays         : 0.000300697354166667
TotalHours        : 0.0072167365
TotalMinutes      : 0.43300419
TotalSeconds      : 25.9802514
TotalMilliseconds : 25980.2514

我已经使用 start-job 进行了尝试:

0..15 | foreach-object {Start-Job -ScriptBlock { Parallel-Delete $filelist $_}}

而且我没有得到我的预期,它成功启动了 16 个实际上什么都不做的作业,所以我把它们全部停止了,我还注意到,“命令”中的变量 $filelist 不是绿色的......所以我没有'不知道函数是否未被识别或变量没有被传递......

而且我尝试了一种我在这里找到的方法: Powershell Start-Process to start Powershell session and pass local variables

有了这个:

$ScriptBlock = {
    function Parallel-Delete {...}
}
remake test folder...
$PowerShell=(Get-Process -Id $pid).path
0..15|%{Start-Process -FilePath $PowerShell -ArgumentList "-Command & {$ScriptBlock Parallel-Delete('$filelist $_')}"}

我已经成功启动了 16 个黑色的 PowerShell 控制台 Windows,它们都显示了这个:

cmdlet Parallel-Delete at command pipeline position 1
Supply values for the following parameters:
number:

这意味着数字未通过,但这也意味着 $filelist 已成功传递(也许),我已经确认带有 scriptblock 的启动过程适用于一个变量,但它未能传递多个变量。

我也知道 Invoke-Expression,虽然我还没有尝试过。目前我认为 start-process 方法更像我想要的——如果我能让它工作的话。

就是这样,如何在n个并行进程中运行具有多个参数的自定义函数,并将多个变量传递给进程,并使它们彼此并发、独立、独立地运行,从而使并行进程的执行速度是产生相同结果的单线程进程的速度的 n 倍?

有人会帮助我吗?任何帮助,将不胜感激。我提前说谢谢。

PS 我在 Windows 10 20H2 上使用 PowerShell 7.1 x64。

更新:我已经尝试了 foreach -parallel:

function Parallel-Delete {
        param(
        [Parameter(Valuefrompipeline=$true, Mandatory=$true, Position=0)] [array]$filelist,
        [Parameter(Valuefrompipeline=$true, Mandatory=$true, Position=1)] [int]$number
        )
        0..($filelist.count-1) | Where-Object {$_ % 16 -eq $number} | foreach {Remove-Item -Path $filelist[$_]}
}
[array]$filelist=(Get-Childitem -Path "C:\test\0" -File -Force).Fullname
0..15|foreach-object -Parallel {
Parallel-Delete $filelist $_
} -ThrottleLimit 16

它给了我 16 次这个错误信息:

Parallel-Delete:
Line |
   2 |  Parallel-Delete $filelist $_
     |  ~~~~~~~~~~~~~~~
     | The term 'Parallel-Delete' is not recognized as a name of a cmdlet, function, script file, or executable program.
Check the spelling of the name, or if a path was included, verify that the path is correct and try again.

所以函数没有被解析,变量也不是绿色的......

现在我已经尝试过:

0..15|foreach-object -Parallel {
-begin {Parallel-Delete {$filelist $_}}
} -ThrottleLimit 16

它只是给了我这个错误:

ParserError:
Line |
   2 |  -begin {Parallel-Delete {$filelist $_}}
     |                                     ~~
     | Unexpected token '$_' in expression or statement.
     

请帮忙...

4

1 回答 1

0

对于故障排除,排除可能干扰您的期望的项目总是好的。为了更接近您的答案,将您的问题减半通常是一个好习惯。在你的具体情况下,问问自己你想证明什么:

  1. 并行运行的 PowerShell 命令应该处理得更快

  2. 我的文件系统似乎没有按预期处理异步命令

恕我直言,这个社区的响应者(包括我自己)对第一个话题比对第二个话题更感兴趣。事实上,如果涉及到2. 文件系统,还涉及很多其他项目(文件系统类型、硬件、磁盘缓存等),您的话题更多地属于超级用户社区。
换句话说,让我们通过处理将主题 1 从文件系统中分离出来Start-Sleep 1

function Parallel-Delete { Start-Sleep 1 }

(Measure-Command { 0..15 | foreach-object { Parallel-Delete } }).TotalMilliseconds
16012.0359

(Measure-Command { 0..15 | foreach-object { Start-Job { Parallel-Delete } } }).TotalMilliseconds
4865.6182

(Measure-Command { 0..15 | foreach-object -Parallel { function Parallel-Delete { Start-Sleep 1 }; Parallel-Delete } }).TotalMilliseconds
4070.8242

这是关于 4 核系统上并行进程的性能差异的预期结果。

于 2020-12-17T13:31:08.507 回答