Perintah batch FOR Windows multithreaded

11

apakah Anda tahu jika ada cara sederhana untuk menjalankan perintah FOR dalam file batch pada banyak utas? Apa gunanya memiliki 4 core jika saya tidak dapat menjalankan tugas saya dalam 4 utas paralel?

Misalnya, jika saya mengoptimalkan PNG dengan PNGOUT, perintah yang akan saya gunakan adalah

for %i in (*.png) do pngout "%i"

Tetapi ini adalah tugas yang sangat dapat dipisah-pisahkan di mana sub-tugas tidak saling bergantung sama sekali.

Untuk menjalankan ini dalam 4 'antrian' saya akan menulis sesuatu seperti

for -thread 4 %i in (*.png) do pngout "%i"

Apakah saya perlu menulis aplikasi seperti untuk saya sendiri yang dapat melakukan ini atau apakah ada solusi gratis yang tersedia?

Axarydax
sumber
periksa jawaban berikut untuk menggunakan alat eksternal: [ stackoverflow.com/a/12041213/365229[[1] [1]: stackoverflow.com/a/12041213/365229
Behrouz.M

Jawaban:

13

Saya telah menulis file batch yang hanya mengeksekusi jumlah maksimum perintah beberapa saat yang lalu di Stack Overflow: Eksekusi paralel dari proses shell :

@echo off
for /l %%i in (1,1,20) do call :loop %%i
goto :eof

:loop
call :checkinstances
if %INSTANCES% LSS 5 (
    rem just a dummy program that waits instead of doing useful stuff
    rem but suffices for now
    echo Starting processing instance for %1
    start /min wait.exe 5 sec
    goto :eof
)
rem wait a second, can be adjusted with -w (-n 2 because the first ping returns immediately;
rem otherwise just use an address that's unused and -n 1)
echo Waiting for instances to close ...
ping -n 2 ::1 >nul 2>&1
rem jump back to see whether we can spawn a new process now
goto loop
goto :eof

:checkinstances
rem this could probably be done better. But INSTANCES should contain the number of running instances afterwards.
for /f "usebackq" %%t in (`tasklist /fo csv /fi "imagename eq wait.exe"^|find /v /c ""`) do set INSTANCES=%%t
goto :eof

Ini memunculkan maksimal empat proses baru yang dieksekusi secara paralel dan diminimalkan. Waktu tunggu perlu disesuaikan mungkin, tergantung pada seberapa banyak setiap proses dan berapa lama itu berjalan. Anda mungkin juga perlu menyesuaikan nama proses yang dicari daftar tugas jika Anda melakukan sesuatu yang lain.

Meskipun demikian, tidak ada cara untuk menghitung dengan benar proses yang dihasilkan oleh kumpulan ini. Salah satu caranya adalah dengan membuat angka acak di awal batch ( %RANDOM%) dan membuat batch pembantu yang melakukan pemrosesan (atau memunculkan program pemrosesan) tetapi yang dapat mengatur judul jendelanya menjadi parameter:

@echo off
title %1
"%2" "%3"

Ini akan menjadi kumpulan sederhana yang menetapkan judulnya ke parameter pertama dan kemudian menjalankan parameter kedua dengan argumen ketiga. Anda kemudian dapat memfilter dalam daftar tugas dengan memilih hanya proses dengan judul jendela yang ditentukan ( tasklist /fi "windowtitle eq ..."). Ini harus bekerja dengan cukup andal dan mencegah terlalu banyak kesalahan positif. Mencari cmd.exeakan menjadi ide yang buruk jika Anda masih memiliki beberapa contoh berjalan, karena membatasi kumpulan proses pekerja Anda.

Anda dapat menggunakan %NUMBER_OF_PROCESSORS%untuk membuat default yang masuk akal dari berapa banyak instance untuk menelurkan.

Anda juga dapat dengan mudah mengadaptasi ini untuk digunakan psexecuntuk menelurkan proses jarak jauh (tetapi tidak akan sangat layak karena Anda harus memiliki hak admin di mesin lain serta memberikan kata sandi dalam batch). Namun, Anda harus menggunakan nama proses untuk memfilter.

Joey
sumber
ini adalah sihir batch hitam yang serius! Saya berharap saya bisa lebih banyak memilih!
Axarydax
Nah, itu hal-hal yang cukup mendasar begitu Anda terbiasa ;-)
Joey
Perintah 'wc' tidak tersedia di baris perintah Win10 saya. Apa yang bisa saya gunakan lagi?
PeterCo
1
@PeterCo: find /c /v "".
Joey
1

File batch adalah untuk skrip yang sangat dasar dan tidak mendukung segala jenis multithreading. Anda perlu menulis utilitas Anda sendiri untuk melakukan apa yang ingin Anda capai.

Atau, Windows PowerShell dapat memberikan lebih banyak kemampuan untuk membuat Anda lebih dekat ke tujuan Anda.

Jika Anda hanya ingin menjalankan beberapa operasi secara bersamaan, Anda dapat menggunakan perintah mulai untuk meluncurkan utilitas PNGOUT di jendela baru. Loop FOR akan terus berlanjut tanpa menunggu setiap operasi selesai.

Baris yang diubah akan terlihat seperti ini:

for %i in (*.png) do start pngout "%i"

Namun, perhatikan bahwa ini akan secara efektif meluncurkan PNGOUT untuk SEMUA file di direktori pada saat yang sama, yang kemungkinan besar tidak diinginkan.

Herohtar
sumber
Ini adalah pendekatan yang naif dan seperti yang Anda sebutkan mungkin tidak diinginkan. Anda hanya ingin meluncurkan sebanyak mungkin proses yang Anda miliki. Jika Anda memiliki 4 core dan 1.000 file, Anda benar-benar ingin memproses hanya 4 sekaligus sampai semua 1.000 diproses. Jika Anda mencoba memproses semua 1.000 sekaligus pada 4 core, komputer Anda akan melambat menjadi perayapan yang tidak berguna.
Adisak