私は 8 GB の RAM を備えた 8 コア CPU を使用しており、7-zip CLI を自動化するバッチ ファイルを作成して、パラメーターと変数の最も強力な組み合わせを見つけることを最終目標として、ほとんどのパラメーターと変数を使い果たし、同じファイル セットを圧縮しています。最小のアーカイブ サイズになる変数。
特に処理するファイルのセットがギガバイト単位の場合、これは本質的に非常に時間がかかります。自動化するだけでなく、このプロセス全体を高速化する方法が必要です。
7-zip はさまざまな圧縮アルゴリズムで動作します。シングル スレッドのみ、マルチスレッド、大量のメモリを必要としないもの、大量のメモリを必要とし、8 GB の壁を超えるものもあります。8 GB を超えるメモリを必要とする組み合わせを除外して、順番に動作する自動バッチを既に正常に作成しました。
プロセス全体を簡素化するために、さまざまな圧縮アルゴリズムをいくつかのバッチに分割しました。たとえば、7z アーカイブとしての PPMd での圧縮では、1 スレッドで最大 1024MB が使用されます。これは私の現在のバッチです:
@echo off
echo mem=1m 2m 3m 4m 6m 8m 12m 16m 24m 32m 48m 64m 96m 128m 192m 256m 384m 512m 768m 1024m
echo o=2 3 4 5 6 7 8 10 12 14 16 20 24 28 32
echo s=off 1m 2m 4m 8m 16m 32m 64m 128m 256m 512m 1g 2g 4g 8g 16g 32g 64g on
echo x=1 3 5 7 9
for %%x IN (9) DO for %%d IN (1024m 768m 512m 384m 256m 192m 128m 96m 64m 48m 32m 24m 16m 12m 8m 6m 4m 3m 2m 1m) DO for %%w IN (32 28 24 20 16 14 12 10 8 7 6 5 4 3 2) DO for %%s IN (on) DO 7z.exe a teste.resultado\%%xx.ppmd.%%dd.%%ww.%%ss.7z .\teste.original\* -mx=%%x -m0=PPMd:mem=%%d:o=%%w -ms=%%s
exit
x
、s
、o
およびmem
はパラメーターであり、それぞれの後に続くのは、7z.exe が使用する変数です。x
この場合は関係ありs
ません。アーカイブの圧縮強度とソリッド ブロック サイズを意味します。
そのバッチは正常に動作しますが、一度に 7z.exe の 1 つのインスタンスのみを実行するように制限されています。現在、8 GB の RAM または 8 スレッドを超えずに、より多くの 7z.exe インスタンスを並行して実行する方法を探しています。シーケンス内の次の作業に進む前に、最初に来た方を一度に実行します。
どうすればこれを改善できますか? いくつかのアイデアがありますが、それらをバッチで機能させる方法がわかりません。私は、7z プロセスとは相互作用しないが、次の 7z インスタンスがいつ開始されるかを制御する 2 つの変数を考えていました。1 つの変数は現在使用中のスレッド数を追跡し、別の変数は使用中のメモリ量を追跡します。それはうまくいくでしょうか?
編集: 申し訳ありませんが、詳細を追加する必要があります。この投稿スタイルは初めてです。この回答に続いて - https://stackoverflow.com/a/19481253/2896127 - 8 つのバッチが作成され、7z.PPMd バッチがその 1 つであることを述べました。おそらく、すべてのバッチをリストし、7z がパラメーターをどのように処理するかによって、問題全体についてより良い洞察が得られるでしょう。簡単なものから始めます。
- 7z.PPMd - 1 つの完全に使用されたスレッドとディクショナリに依存する、インスタンスあたりの 32m ~ 1055m のメモリ使用量。
- 7z.BZip2 - 完全に使用された 8 つのスレッドと、インスタンスあたりの固定 109m のメモリ使用量。
- zip.Bzip2 - 部分的に使用された 8 つのスレッドと、インスタンスごとに固定された 336m のメモリ使用量。
- zip.Deflate - 部分的に使用された 8 つのスレッドと、インスタンスごとに固定された 260m のメモリ使用量。
- zip.PPMd - 部分的に使用された 8 つのスレッドとディクショナリに依存する 280m ~ 2320m のインスタンスあたりのメモリ使用量。
部分的に使用されたスレッドとは、各 7.exe インスタンスで使用される 8 つのスレッドを割り当てている間、アルゴリズムはランダムな方法で可変 CPU 使用率を行うことができ、制御不能で予測不可能ですが、制限がそこに設定されていることを意味します。 - 8 スレッド以下。8 つの完全に使用されたスレッドの場合、8 コア CPU では、各インスタンスが CPU の 100% を使用していることを意味します。
最も複雑なもの - 7z.LZMA、7z.LZMA2、zip.LZMA - について詳しく説明する必要がありますが、今は時間がありません。暇ができたら、LZMA の部分を編集するために戻ってきます。
再度、感謝します。
編集:LZMA部分に追加。
7z.LZMA - 各インスタンスは n スレッドで、範囲は 1 から 2 です。
- 1 つの完全に使用されたスレッド、ディクショナリ依存、64k から 512m:
- 64k の辞書は 32m のメモリを使用します
- ...
- 512m 辞書は 5407m メモリを使用します
- 除外範囲: 768m ~ 1024m (使用可能なメモリの制限 8192m を超えています)
- 2 つの部分的に使用されたスレッド、ディクショナリ依存、64k から 512m:
- 64k の辞書は 38m のメモリを使用します
- ...
- 512m 辞書は 5413m メモリを使用します
- 除外範囲: 768m ~ 1024m (使用可能なメモリの制限 8192m を超えています)
- 1 つの完全に使用されたスレッド、ディクショナリ依存、64k から 512m:
7z.LZMA2 - 各インスタンスは n スレッドで、範囲は 1 から 8 です。
- 1 つの完全に使用されたスレッド、ディクショナリ依存、64k から 512m:
- 64k の辞書は 32m のメモリを使用します
- ...
- 512m 辞書は 5407m メモリを使用します
- 除外範囲: 768m ~ 1024m (使用可能なメモリの制限 8192m を超えています)
- 2 つまたは 3 つの部分的に使用されたスレッド、ディクショナリ依存、64k から 512m:
- 64k の辞書は 38m のメモリを使用します
- ...
- 512m 辞書は 5413m メモリを使用します
- 除外範囲: 768m ~ 1024m (使用可能なメモリの制限 8192m を超えています)
- 4 つまたは 5 つの部分的に使用されたスレッド、ディクショナリ依存、64k から 256m:
- 64k の辞書は 51m のメモリを使用します
- ...
- 256m の辞書は 5677m のメモリを使用します
- 除外範囲: 384m ~ 1024m (利用可能なメモリの制限 8192m を超えています)
- 6 つまたは 7 つの部分的に使用されたスレッド、ディクショナリ依存、64k から 192m:
- 64k 辞書は 62m メモリを使用します
- ...
- 192m の辞書は 6965m のメモリを使用します
- 除外範囲: 256m ~ 1024m (使用可能なメモリの制限 8192m を超えています)
- 8 つの部分的に使用されたスレッド、ディクショナリ依存、64k から 128m:
- 64k の辞書は 72m のメモリを使用します
- ...
- 128m の辞書は 6717m のメモリを使用します
- 除外範囲: 192m ~ 1024m (使用可能なメモリの制限 8192m を超えています)
- 1 つの完全に使用されたスレッド、ディクショナリ依存、64k から 512m:
zip.LZMA - 各インスタンスは 1 から 8 までの n スレッドです。
- 1 つの完全に使用されたスレッド、ディクショナリ依存、64k から 512m:
- 64k の辞書は 3m のメモリを使用します
- ...
- 512m 辞書は 5378m メモリを使用します
- 除外範囲: 768m ~ 1024m (使用可能なメモリの制限 8192m を超えています)
- 2 つまたは 3 つの部分的に使用されたスレッド、ディクショナリ依存、64k から 512m:
- 64k の辞書は 9m のメモリを使用します
- ...
- 512m 辞書は 5384m メモリを使用します
- 除外範囲: 768m ~ 1024m (使用可能なメモリの制限 8192m を超えています)
- 4 つまたは 5 つの部分的に使用されたスレッド、ディクショナリ依存、64k から 256m:
- 64k の辞書は 82m のメモリを使用します
- ...
- 256m の辞書は 5456m のメモリを使用します
- 除外範囲: 384m ~ 1024m (利用可能なメモリの制限 8192m を超えています)
- 6 つまたは 7 つの部分的に使用されたスレッド、ディクショナリ依存、64k から 256m:
- 64k の辞書は 123m のメモリを使用します
- ...
- 256m 辞書は 8184m を使用します (制限に非常に近いですが、除外することを検討する場合があります)
- 除外範囲: 384m ~ 1024m (利用可能なメモリの制限 8192m を超えています)
- 8 つの部分的に使用されたスレッド、ディクショナリ依存、64k から 128m:
- 64k の辞書は 164m のメモリを使用します
- ...
- 128m の辞書は 5536m のメモリを使用します
- 除外範囲: 192m ~ 1024m (使用可能なメモリの制限 8192m を超えています)
- 1 つの完全に使用されたスレッド、ディクショナリ依存、64k から 512m:
nul を含むコマンドの動作を理解しようとしています。その部分で何が起こっているのか、これらの記号 ^ > ^&1 "" が何を意味しているのか、よくわかりません。
2>nul del %lock%!nextProc!
%= Redirect the lock handle to the lock file. The CMD process will =%
%= maintain an exclusive lock on the lock file until the process ends. =%
start /b "" cmd /c %lockHandle%^>"%lock%!nextProc!" 2^>^&1 !cpu%%N! !cmd!
)
set "launch="
その後、:wait コードで:
) 9>>"%lock%%%N"
) 2>nul
if %endCount% lss %startCount% (
1>nul 2>nul ping /n 2 ::1
goto :wait
)
2>nul del %lock%*
編集 2 (29-10-2013): 状況の現在のポイントを追加します。
試行錯誤の調査の後、何が起こっているのかを段階的にメモして補完した結果、上記の動作を理解することができました。start コマンドを使用して行を単純化すると、次のようになります。
start /b /low cmd /c !cmd!>"%lock%!nextProc!"
動作しますが、まだ意味がわかりません1^>"filename" 2^>^&1 'command'
。ファイル名にテキストを書き込むことに関連していることは知っていますが、そうでなければ私に表示されます。この場合、7z.exe テキストのすべてが表示されますが、ファイルに書き込まれます。7z.exe インスタンスがジョブを完了するまで、ファイルには何も書き込まれませんが、ファイルは既に存在しますが、同時に存在しません。7z.exe が実際に終了すると、ファイルはファイナライズされ、今度はスクリプトの次の部分のために存在します。
これで、提案されたスクリプトの処理動作を理解できるようになり、それを独自のもので補完しています。すべてのバッチを「1 つのバッチですべて実行」スクリプトに実装しようとしています。簡易版では、これは次のとおりです。
echo 8 threads - maxproc=1
for %%x IN (9) DO for %%t IN (8) DO for %%d IN (900k) DO for %%s IN (on) DO 7z.exe a teste.resultado\%%xx.bzip2.%%tt.%%dd.%%ss.7z .\teste.original\* -mx=%%x -ms=%%s -m0=BZip2:d=%%d:mt=%%t
for %%x IN (9) DO for %%t IN (8) DO for %%d IN (900k) DO 7z.exe a teste.resultado\%%xx.bzip2.%%tt.%%dd.zip .\teste.original\* -mx=%%x -mm=BZip2:d=%%d -mmt=%%t
for %%x IN (9) DO for %%t IN (8) DO for %%w IN (257 256 192 128 96 64 48 32 24 16 12 8) DO 7z.exe a teste.resultado\%%xx.deflate64.%%tt.%%ww.zip .\teste.original\* -mx=%%x -mm=deflate64:fb=%%w -mmt=%%t
for %%x IN (9) DO for %%t IN (8) DO for %%w IN (258 256 192 128 96 64 48 32 24 16 12 8) DO 7z.exe a teste.resultado\%%xx.deflate.%%tt.%%ww.zip .\teste.original\* -mx=%%x -mm=deflate:fb=%%w -mmt=%%t
for %%x IN (9) DO for %%t IN (8) DO for %%d IN (256m 128m 64m 32m 16m 8m 4m 2m 1m) DO for %%w IN (16 15 14 13 12 11 10 9 8 7 6 5 4 3 2) DO 7z.exe a teste.resultado\%%xx.ppmd.%%tt.%%dd.%%ww.zip .\teste.original\* -mx=%%x -mm=PPMd:mem=%%d:o=%%w -mmt=%%t
echo 4 threads - maxproc=2
for %%x IN (9) DO for %%t IN (4) DO for %%d IN (256m) DO for %%w IN (273 256 192 128 96 64 48 32 24 16 12 8) DO for %%s IN (on) DO 7z.exe a teste.resultado\%%xx.lzma2.%%tt.%%dd.%%ww.%%ss.7z .\teste.original\* -mx=%%x -ms=%%s -m0=lzma2:d=%%d:fb=%%w -mmt=%%t
echo 2 threads - maxproc=4
for %%x IN (9) DO for %%t IN (2) DO for %%d IN (512m) DO for %%w IN (273 256 192 128 96 64 48 32 24 16 12 8) DO for %%s IN (on) DO 7z.exe a teste.resultado\%%xx.lzma.%%tt.%%dd.%%ww.%%ss.7z .\teste.original\* -mx=%%x -ms=%%s -m0=LZMA:d=%%d:fb=%%w -mmt=%%t
for %%x IN (9) DO for %%t IN (2) DO for %%d IN (512m) DO for %%w IN (273 256 192 128 96 64 48 32 24 16 12 8) DO for %%s IN (on) DO 7z.exe a teste.resultado\%%xx.lzma2.%%tt.%%dd.%%ww.%%ss.7z .\teste.original\* -mx=%%x -ms=%%s -m0=lzma2:d=%%d:fb=%%w -mmt=%%t
for %%x IN (9) DO for %%t IN (2) DO for %%d IN (512m) DO for %%w IN (273 256 192 128 96 64 48 32 24 16 12 8) DO 7z.exe a teste.resultado\%%xx.lzma.%%tt.%%dd.%%ww.zip .\teste.original\* -mx=%%x -mm=lzma:d=%%d:fb=%%w -mmt=%%t
echo 1 threads - maxproc=8
for %%x IN (9) DO for %%t IN (1) DO for %%d IN (512m) DO for %%w IN (273 256 192 128 96 64 48 32 24 16 12 8) DO for %%s IN (on) DO 7z.exe a teste.resultado\%%xx.lzma.%%tt.%%dd.%%ww.%%ss.7z .\teste.original\* -mx=%%x -ms=%%s -m0=LZMA:d=%%d:fb=%%w -mmt=%%t
for %%x IN (9) DO for %%t IN (1) DO for %%d IN (512m) DO for %%w IN (273 256 192 128 96 64 48 32 24 16 12 8) DO for %%s IN (on) DO 7z.exe a teste.resultado\%%xx.lzma2.%%tt.%%dd.%%ww.%%ss.7z .\teste.original\* -mx=%%x -ms=%%s -m0=lzma2:d=%%d:fb=%%w -mmt=%%t
for %%x IN (9) DO for %%d IN (1024m 768m 512m 384m 256m 192m 128m 96m 64m 48m 32m 24m 16m 12m 8m 6m 4m 3m 2m 1m) DO for %%w IN (32 28 24 20 16 14 12 10 8 7 6 5 4 3 2) DO for %%s IN (on) DO 7z.exe a teste.resultado\%%xx.ppmd.%%dd.%%ww.%%ss.7z .\teste.original\* -mx=%%x -m0=PPMd:mem=%%d:o=%%w -ms=%%s
for %%x IN (9) DO for %%t IN (1) DO for %%d IN (512m) DO for %%w IN (273 256 192 128 96 64 48 32 24 16 12 8) DO 7z.exe a teste.resultado\%%xx.lzma.%%tt.%%dd.%%ww.zip .\teste.original\* -mx=%%x -mm=lzma:d=%%d:fb=%%w -mmt=%%t
つまり、可能な限り最も効率的な方法ですべてを処理したいと考えています。一度に実行できるプロセスの数を決定する方法もありますが、各プロセスに必要なメモリもあるため、それらのプロセスに必要なすべてのメモリの合計が 8192 MB を超えないようにします。私はこの部分を機能させました。
@echo off
setlocal enableDelayedExpansion
set "maxMem=8192"
set "maxThreads=8"
:cycle1
set "cycleCount=4"
set "cycleThreads=1"
set "maxProc="
set /a "maxProc=maxThreads/cycleThreads"
set "cycleFor1=for %%x IN (9) DO for %%t IN (1) DO for %%d IN (512m) DO for %%w IN (273 256 192 128 96 64 48 32 24 16 12 8) DO for %%s IN (on) DO ("
set "cycleFor2=for %%x IN (9) DO for %%t IN (1) DO for %%d IN (512m) DO for %%w IN (273 256 192 128 96 64 48 32 24 16 12 8) DO for %%s IN (on) DO ("
set "cycleFor3=for %%x IN (9) DO for %%d IN (1024m 768m 512m 384m 256m 192m 128m 96m 64m 48m 32m 24m 16m 12m 8m 6m 4m 3m 2m 1m) DO for %%w IN (32 28 24 20 16 14 12 10 8 7 6 5 4 3 2) DO for %%s IN (on) DO ("
set "cycleFor4=for %%x IN (9) DO for %%t IN (1) DO for %%d IN (512m) DO for %%w IN (273 256 192 128 96 64 48 32 24 16 12 8) DO ("
set "cycleCmd1=7z.exe a teste.resultado\%%xx.lzma.%%tt.%%dd.%%ww.%%ss.7z .\teste.original\* -mx=%%x -ms=%%s -m0=LZMA:d=%%d:fb=%%w -mmt=%%t"
set "cycleCmd2=7z.exe a teste.resultado\%%xx.lzma2.%%tt.%%dd.%%ww.%%ss.7z .\teste.original\* -mx=%%x -ms=%%s -m0=lzma2:d=%%d:fb=%%w -mmt=%%t"
set "cycleCmd3=7z.exe a teste.resultado\%%xx.ppmd.%%dd.%%ww.%%ss.7z .\teste.original\* -mx=%%x -m0=PPMd:mem=%%d:o=%%w -ms=%%s"
set "cycleCmd4=7z.exe a teste.resultado\%%xx.lzma.%%tt.%%dd.%%ww.zip .\teste.original\* -mx=%%x -mm=lzma:d=%%d:fb=%%w -mmt=%%t"
set "tempMem1=5407"
set "tempMem2=5407"
set "tempMem3=1055"
set "tempMem4=5378"
rem set "tempMem1=5407"
rem set "tempMem2=5407"
rem set "tempMem3=1055 799 543 415 287 223 159 127 95 79 63 55 47 43 39 37 35 34 33 32"
rem set "tempMem4=5378"
set "memSum=0"
if not defined memRem set "memRem=!maxMem!"
for /l %%N in (1 1 %cycleCount%) DO (set "tempProc%%N=")
for /l %%N in (1 1 %cycleCount%) DO (
set memRem
set /a "tempProc%%N=%memRem%/tempMem%%N"
set /a "memSum+=tempMem%%N"
set /a "memRem-=tempMem%%N"
set /a "maxProc=!tempProc%%N!"
call :executeCycle
set /a "memRem+=tempMem%%N"
set /a "memSum-=tempMem%%N"
set /a "maxProc-=!tempProc%%!
)
goto :fim
:executeCycle
set "lock=lock_%random%_"
set /a "startCount=0, endCount=0"
for /l %%N in (1 1 %maxProc%) DO set "endProc%%N="
set launch=1
for %%x IN (9) DO for %%t IN (1) DO for %%d IN (512m) DO for %%w IN (273 256 192 128 96 64 48 32 24 16 12 8) DO for %%s IN (on) DO (
set "cmd=7z.exe a teste.resultado\%%xx.lzma.%%tt.%%dd.%%ww.%%ss.7z .\teste.original\* -mx=%%x -ms=%%s -m0=LZMA:d=%%d:fb=%%w -mmt=%%t"
if !startCount! lss %maxProc% (
set /a "startCount+=1, nextProc=startCount"
) else (
call :wait
)
set cmd!nextProc!=!cmd!
echo !time! - proc!nextProc!: starting !cmd!
2>nul del %lock%!nextProc!
start /b /low cmd /c !cmd!>"%lock%!nextProc!"
)
set "launch="
:wait
for /l %%N in (1 1 %startCount%) do (
if not defined endProc%%N if exist "%lock%%%N" (
echo !time! - proc%%N: finished !cmd%%N!
if defined launch (
set nextProc=%%N
exit /b
)
set /a "endCount+=1, endProc%%N=1"
) 9>>"%lock%%%N"
) 2>nul
if %endCount% lss %startCount% (
1>nul 2>nul ping /n 2 ::1
goto :wait
)
2>nul del %lock%*
echo ===
echo Thats all folks!
exit /b
:fim
pause
問題がcycleFor1
ありcycleCmd1
、一部に配置されています-意図したとおりに機能させるには、行と 内の最初の変数を:cycle1
置き換える必要があります。それ、どうやったら出来るの?for
cmd
:executeCycle
私が持っている他の問題は約tempMem3
です。コマンドの実行時に必要なすべてのメモリを記録しましたcycleCmd3
。辞書依存です。tempMem3 と cycleCmd3 は次のように関連付けられています。
for %%d IN (1024m 768m 512m 384m 256m 192m 128m 96m 64m 48m 32m 24m 16m 12m 8m 6m 4m 3m 2m 1m) DO
set "tempMem3=1055 799 543 415 287 223 159 127 95 79 63 55 47 43 39 37 35 34 33 32"
したがって、1024m は 1055 を使用し、768m は 799 を使用し、1m は 32 を使用するまで続きます。それをスクリプトに変換する方法がわかりません。
どんな助けでも大歓迎です。