Saya memiliki masalah scripting shell di mana saya diberi direktori yang penuh dengan file input (setiap file yang mengandung banyak baris input), dan saya perlu memprosesnya secara individual, mengarahkan setiap output mereka ke file yang unik (alias, file_1.input perlu untuk ditangkap dalam file_1.output, dan sebagainya).
Pra-paralel , saya hanya akan mengulangi setiap file dalam direktori dan melakukan perintah saya, sambil melakukan semacam timer / teknik penghitungan untuk tidak membanjiri prosesor (dengan asumsi bahwa setiap proses memiliki runtime konstan). Namun, saya tahu itu tidak akan selalu menjadi masalah, jadi menggunakan solusi "paralel" sepertinya merupakan cara terbaik untuk mendapatkan skrip shell multi-threading tanpa menulis kode khusus.
Sementara saya telah memikirkan beberapa cara untuk menyiapkan paralel untuk memproses masing-masing file ini (dan memungkinkan saya untuk mengelola inti saya secara efisien), mereka semua tampak berantakan. Saya memiliki apa yang saya pikir adalah kasus penggunaan yang cukup mudah, jadi akan lebih memilih untuk menjaganya sebersih mungkin (dan tidak ada dalam contoh paralel yang tampaknya melompat keluar sebagai masalah saya.
Bantuan apa pun akan dihargai!
contoh direktori input:
> ls -l input_files/
total 13355
location1.txt
location2.txt
location3.txt
location4.txt
location5.txt
Naskah:
> cat proces_script.sh
#!/bin/sh
customScript -c 33 -I -file [inputFile] -a -v 55 > [outputFile]
Pembaruan : Setelah membaca jawaban Ole di bawah ini, saya dapat mengumpulkan potongan-potongan yang hilang untuk implementasi paralel saya sendiri. Meskipun jawabannya bagus, berikut adalah penelitian tambahan dan catatan yang saya ambil:
Alih-alih menjalankan proses penuh saya, saya pikir mulai dengan bukti perintah konsep untuk membuktikan solusinya di lingkungan saya. Lihat dua implementasi saya yang berbeda (dan catatan):
find /home/me/input_files -type f -name *.txt | parallel cat /home/me/input_files/{} '>' /home/me/output_files/{.}.out
Penggunaan menemukan (bukan ls, yang dapat menyebabkan masalah) untuk menemukan semua file yang berlaku dalam direktori file input saya, dan kemudian mengalihkan kontennya ke direktori dan file terpisah. Masalah saya di atas adalah membaca dan mengarahkan ulang (skrip yang sebenarnya sederhana), jadi mengganti skrip dengan kucing adalah bukti konsep yang bagus.
parallel cat '>' /home/me/output_files/{.}.out ::: /home/me/input_files/*
Solusi kedua ini menggunakan paradigma input variabel paralel untuk membaca file dalam, namun untuk pemula, ini jauh lebih membingungkan. Bagi saya, menggunakan find a dan pipa memenuhi kebutuhan saya dengan baik.
sumber
Cara standar untuk melakukan ini adalah dengan mengatur antrian dan menelurkan sejumlah pekerja yang tahu cara menarik sesuatu dari antrian dan memprosesnya. Anda dapat menggunakan fifo (pipa bernama bernama) untuk komunikasi antara proses ini.
Di bawah ini adalah contoh naif untuk menunjukkan konsep tersebut.
Skrip antrian sederhana:
Dan seorang pekerja:
process_file
dapat didefinisikan di suatu tempat di pekerja Anda, dan dapat melakukan apa pun yang Anda butuhkan untuk dilakukan.Setelah Anda memiliki dua potong itu, Anda dapat memiliki monitor sederhana yang memulai proses antrian dan sejumlah proses pekerja.
Skrip monitor:
Itu dia. Jika Anda benar-benar melakukan ini, lebih baik untuk mengatur fifo di monitor, dan meneruskan jalur ke antrian dan pekerja, sehingga mereka tidak digabungkan dan tidak terjebak ke lokasi tertentu untuk fifo. Saya mengaturnya dengan cara ini di jawaban khusus sehingga jelas apa yang Anda gunakan saat Anda membacanya.
sumber
monitor_workers
sama sepertiprocess_file
- itu adalah fungsi yang melakukan apa pun yang Anda inginkan. Tentang monitor - Anda benar; itu harus menyimpan pids dari para pekerjanya (sehingga dapat mengirim sinyal mematikan) dan penghitung perlu bertambah ketika mulai pekerja. Saya sudah mengedit jawaban untuk memasukkan itu.parallel
. Saya pikir itu adalah ide Anda, sepenuhnya diimplementasikan.Contoh lain:
Saya menemukan contoh-contoh lain yang tidak perlu rumit, ketika dalam kebanyakan kasus di atas adalah apa yang mungkin Anda cari.
sumber
Alat yang tersedia secara umum yang dapat melakukan paralelisasi adalah make. GNU make dan beberapa lainnya memiliki
-j
opsi untuk melakukan build paralel.Jalankan
make
seperti ini (saya berasumsi nama file Anda tidak mengandung karakter khusus,make
tidak baik dengan itu):sumber
Ini untuk melakukan perintah yang sama pada sejumlah besar file di direktori saat ini:
Ini menjalankan
customScript
pada setiaptxt
file, menempatkan output dalamouttxt
file. Ubah sesuai kebutuhan. Kunci untuk mendapatkan ini berfungsi adalah pemrosesan sinyal, menggunakan SIGUSR1 sehingga proses anak dapat membuat proses induk tahu bahwa itu dilakukan. Menggunakan SIGCHLD tidak akan berfungsi karena sebagian besar pernyataan dalam skrip akan menghasilkan sinyal SIGCHLD ke skrip shell. Saya mencoba ini mengganti perintah Anda dengansleep 1
, program menggunakan 0,28 cpu pengguna dan 0,14 cpu sistem; ini hanya ada di sekitar 400 file.sumber
wait
yang cukup 'pintar'; tetapi akan kembali setelah mendapatkanSIGUSR1
sinyal. Anak / pekerja mengirimSIGUSR1
ke orang tua, yang tertangkap (trap
), dan pengurangan$worker
(trap
klausa) dan kembali secara tidak normalwait
, memungkinkanif [ $worker -lt $num_workers ]
klausa untuk mengeksekusi.Atau cukup gunakan
xargs -P
, tidak perlu menginstal perangkat lunak tambahan:Sedikit penjelasan untuk opsi:
-I'XXX'
set string yang akan diganti dalam templat perintah dengan nama file-P4
akan menjalankan 4 proses secara paralel-n1
akan menempatkan hanya satu file per eksekusi walaupun dua XXX ditemukan-print0
dan-0
bekerja bersama, memungkinkan Anda memiliki karakter khusus (seperti spasi) dalam nama filesumber