4

43 TB までのメディア ドライブを多数備えたサーバーがあります。ビンロウジュ 1882ix-16 は、ほとんどの場合、個々のドライブが使用されていないため、30 分間非アクティブになった後にドライブをスピンダウンするように設定されています。これは、不要な電力と熱を防ぐためにうまく機能します。この場合、ドライブは引き続き Windows エクスプローラーに表示されますが、クリックしてアクセスすると、ドライブがスピンアップするのを待たなければならないため、フォルダー リストが表示されるまでに約 10 秒かかります。

管理作業のために、すべてのドライブを起動して検索できるようにする必要があります。Windows エクスプローラーで各ドライブをクリックし、スピンアップするのを待ってから次のドライブをクリックするのは非常に面倒です。複数のエクスプローラー ウィンドウを使用すると明らかに高速になりますが、それでも面倒です。私は、powershell スクリプトが痛みを和らげてくれるのではないかと考えました。

そこで、次のことから始めました。

$mediaDrives = @('E:', 'F:', 'G:', 'H:', 'I:', 'J:', 'K:', 'L:',
    'M:','N:', 'O:', 'P:', 'Q:', 'R:', 'S:')
get-childitem $mediaDrives  | foreach-object -process { $_.Name }

これは、アレイ内の各ドライブのルート フォルダ名がリストされていることを要求しているだけです。これはドライブをウェイクアップするために機能しますが、これも線形関数です。スクリプトは、印刷前にドライブごとに一時停止します。各ドライブを同時に起動する方法に関する解決策を探しています。マルチスレッドなどの方法はありますか?

4

4 に答える 4

2

必要な処理を実行するスクリプトを次に示しますが、MTA スレッド モードを使用して powershell で実行する必要があります (これは powershell.exe 2.0 の既定ですが、powershell.exe 3.0 は -MTA スイッチを使用して起動する必要があります)。

#require -version 2.0

# if running in ISE or in STA console, abort
if (($host.runspace.apartmentstate -eq "STA") -or $psise) {
    write-warning "This script must be run under powershell -MTA"
    exit
}

$mediaDrives = @('E:', 'F:', 'G:', 'H:', 'I:', 'J:', 'K:', 'L:',
    'M:','N:', 'O:', 'P:', 'Q:', 'R:', 'S:')

# create a pool of 8 runspaces   
$pool = [runspacefactory]::CreateRunspacePool(1, 8)
$pool.Open()

$jobs = @()
$ps = @()
$wait = @()     

$count = $mediaDrives.Length

for ($i = 0; $i -lt $count; $i++) {

    # create a "powershell pipeline runner"
    $ps += [powershell]::create()  

    # assign our pool of 8 runspaces to use
    $ps[$i].runspacepool = $pool   

    # add wake drive command
    [void]$ps[$i].AddScript(
        "dir $($mediaDrives[$i]) > `$null")

    # start script asynchronously    
    $jobs += $ps[$i].BeginInvoke();         

    # store wait handles for WaitForAll call
    $wait += $jobs[$i].AsyncWaitHandle
}

# wait 5 minutes for all jobs to finish (configurable)
$success = [System.Threading.WaitHandle]::WaitAll($wait,
    (new-timespan -Minutes 5))     
write-host "All completed? $success"

# end async call   
for ($i = 0; $i -lt $count; $i++) {     
    write-host "Completing async pipeline job $i"    

    try {       
        # complete async job           
        $ps[$i].EndInvoke($jobs[$i])     
    } catch {   
        # oops-ee!          
        write-warning "error: $_"      
    }   

    # dump info about completed pipelines       
    $info = $ps[$i].InvocationStateInfo

    write-host "State: $($info.state) ; Reason: $($info.reason)"  
}

したがって、たとえば、次のように保存しwarmup.ps1て実行します。powershell -mta c:\scripts\warmup.ps1

実行空間プールと上記の一般的な手法の詳細については、実行空間プールに関する私のブログ エントリをご覧ください。

http://nivot.org/blog/post/2009/01/22/CTP3TheRunspaceFactoryAndPowerShellAccelerators

私は並列度としてほぼ恣意的に 8 を選択しました。これより低い数値または大きい数値を試してみてください。

于 2012-12-27T17:39:18.107 に答える
1

ドライブごとに個別の PowerShell インスタンスを起動するか、PowerShell 3.0 のワークフローを使用します。とにかく、ドライブを Path パラメーターに直接渡し、Foreach-Object をすべてスキップすることができます。

Get-ChildItem $mediaDrives
于 2012-12-27T10:02:16.150 に答える
1

Start-Jobコマンドレットを使用してこれにアプローチすることを検討しましたか?

$mediaDrives = @('E:', 'F:', 'G:', 'H:', 'I:', 'J:', 'K:')
$mediaDrives | ForEach-Object {
  Start-Job -ArgumentList $_ -ScriptBlock {param($drive)
    Get-ChildItem $drive
  }
}

唯一の巧妙な部分は、Start-Job コマンドレットで -ArgumentList パラメーターを使用して、反復ごとに正しい値を渡す必要があることです。これにより、スクリプトの実行と並行して実行されるバックグラウンド タスクが作成されます。興味があれば

于 2013-01-01T22:01:29.493 に答える
0

待ちたくない場合は、待つ必要はありません。これらのモーニング コールをバックグラウンドで開始します。

bash一つに書くだろう

foreach drive ($mediadrives) {tickle_and_wake $drive &}

(アンパサンドに注意してください。つまり、バックグラウンドでコマンドを開始し、完了するまで待たないでください

PowerShell では、次のように変換されます

foreach ($drive in $mediadrives)  {
   Start-Job {param($d) tickle_and_wake $d} -Arg $drive 
}

すべてのバックグラウンド ジョブが完了したことを確認する場合は、waitinbashまたはWait-Jobin Powershellを使用します。

于 2012-12-31T11:38:23.630 に答える