Chociaż zrobienie tego od razu bash
jest prawdopodobnie niemożliwe, możesz dość łatwo zrobić półprawo. bstark
dał dobre przybliżenie racji, ale ma następujące wady:
- Dzielenie słów: nie możesz przekazać mu żadnych zadań, które używają któregokolwiek z następujących znaków w swoich argumentach: spacje, tabulatory, znaki nowej linii, gwiazdki, znaki zapytania. Jeśli to zrobisz, sytuacja prawdopodobnie nieoczekiwanie się zepsuje.
- Reszta Twojego skryptu nie zawiera niczego w tle. Jeśli to zrobisz lub później dodasz coś do skryptu, który zostanie wysłany w tle, ponieważ zapomniałeś, że nie możesz używać zadań w tle z powodu jego fragmentu, wszystko się zepsuje.
Inne przybliżenie, które nie ma tych wad, jest następujące:
scheduleAll() {
local job i=0 max=4 pids=()
for job; do
(( ++i % max == 0 )) && {
wait "${pids[@]}"
pids=()
}
bash -c "$job" & pids+=("$!")
done
wait "${pids[@]}"
}
Zwróć uwagę, że ten można łatwo dostosować, aby sprawdzić również kod zakończenia każdego zadania po jego zakończeniu, aby można było ostrzec użytkownika, jeśli zadanie się nie powiedzie, lub ustawić kod zakończenia w scheduleAll
zależności od liczby zadań, które zakończyły się niepowodzeniem, lub coś innego.
Problem z tym kodem jest taki, że:
- Planuje cztery (w tym przypadku) zadania naraz, a następnie czeka na zakończenie wszystkich czterech. Niektóre mogą zostać wykonane wcześniej niż inne, co spowoduje, że kolejna partia czterech zadań będzie czekać, aż zostanie wykonana najdłuższa z poprzedniej.
Rozwiązanie, które rozwiązuje ten ostatni problem, musiałoby użyć kill -0
do sondowania, czy któryś z procesów zniknął, zamiast wait
i zaplanowania następnego zadania. Jednak wprowadza to mały nowy problem: między zakończeniem zadania a kill -0
sprawdzeniem, czy się skończył , występuje wyścig . Jeśli zadanie się zakończyło, a inny proces w systemie zostanie uruchomiony w tym samym czasie, biorąc losowy PID, który jest taki sam, jak zadanie, które właśnie się zakończyło, kill -0
nie zauważą, że praca została zakończona i wszystko znowu się zepsuje.
Idealne rozwiązanie nie jest możliwe w bash
.