Mam zadanie, które przetwarza listę plików na stdin. Czas uruchamiania programu jest znaczny, a ilość czasu, jaką zajmuje każdy plik, jest bardzo różna. Chcę odrodzić znaczną liczbę tych procesów, a następnie wysłać pracę do tych, które nie są zajęte. Istnieje kilka różnych narzędzi wiersza polecenia, które prawie robią to, co chcę, zawęziłem to do dwóch prawie działających opcji:
find . -type f | split -n r/24 -u --filter="myjob"
find . -type f | parallel --pipe -u -l 1 myjob
Problem polega na tym, że split
robi czysty round-robin, więc jeden z procesów pozostaje w tyle i pozostaje w tyle, opóźniając zakończenie całej operacji; podczas gdy parallel
chce odrodzić jeden proces na N linii lub bajtów danych wejściowych, a ja spędzam zbyt dużo czasu na narzutach związanych z uruchamianiem.
Czy istnieje coś takiego, który ponownie wykorzysta procesy i linie zasilające do tych procesów, które mają odblokowane standardowe wejścia?
źródło
split
polecenie? Nazwa jest w konflikcie ze standardowym narzędziem do przetwarzania tekstu.myjob
jest gotowa na otrzymanie większej ilości informacji. Nie ma sposobu, aby wiedzieć, że program jest gotowy do przetworzenia większej ilości danych wejściowych, wszystko, co możesz wiedzieć, to to, że gdzieś bufor (bufor potoku, bufor stdio) jest gotowy na przyjęcie większej ilości danych wejściowych. Czy możesz zorganizować wysyłanie przez program jakiegoś żądania (np. Wyświetlenie monitu), gdy będzie ono gotowe?read
wywołania, załatwi sprawę . To dość duże przedsięwzięcie programistyczne.-l 1
wparallel
args? IIRC, który mówi równolegle, aby przetwarzał jeden wiersz danych wejściowych na zadanie (tj. Jedną nazwę pliku na rozwidlenie mojej pracy, więc dużo początkowego obciążenia).Odpowiedzi:
To nie wydaje się możliwe w tak ogólnym przypadku. Oznacza to, że masz bufor dla każdego procesu i możesz oglądać bufory z zewnątrz, aby zdecydować, gdzie umieścić następny wpis (planowanie) ... Oczywiście możesz coś napisać (lub użyć systemu wsadowego takiego jak slurm)
Ale w zależności od tego, jaki jest proces, możesz być w stanie wstępnie przetworzyć dane wejściowe. Na przykład, jeśli chcesz pobrać pliki, zaktualizować wpisy z DB lub podobnego, ale 50% z nich zostanie pominiętych (i dlatego masz dużą różnicę przetwarzania w zależności od danych wejściowych), po prostu skonfiguruj procesor wstępny weryfikuje, które wpisy potrwają długo (plik istnieje, dane zostały zmienione itp.), więc gwarantuje, że wszystko, co pochodzi z drugiej strony, zajmie dość dużo czasu. Nawet jeśli heurystyka nie jest doskonała, możesz skończyć ze znaczną poprawą. Możesz zrzucić pozostałe do pliku i przetworzyć później w ten sam sposób.
Ale to zależy od przypadku użycia.
źródło
Nie, nie ma ogólnego rozwiązania. Twój dyspozytor musi wiedzieć, kiedy każdy program jest gotowy do odczytania innej linii, i nie ma standardu, o którym wiem, który na to pozwala. Wszystko, co możesz zrobić, to umieścić linię na STDOUT i poczekać, aż coś zużyje; producent nie może w dobry sposób stwierdzić, czy następny konsument jest gotowy, czy nie.
źródło
Nie wydaje mi się W moim ulubionym magazynie był kiedyś artykuł na temat programowania bash, który zrobił to, co chciałeś. Jestem skłonny uwierzyć, że gdyby istniały narzędzia do tego, wspomniałyby o nich. Więc chcesz coś w stylu:
Oczywiście możesz zmienić wywołanie na faktycznie działający skrypt według własnych upodobań. Magazyn, o którym wspominałem, początkowo zajmuje się zakładaniem rur i rozpoczynaniem wątków roboczych. Sprawdź
mkfifo
to, ale ta trasa jest o wiele bardziej skomplikowana, ponieważ procesy robocze muszą sygnalizować procesowi nadrzędnemu, że są gotowi na przyjęcie większej ilości danych. Potrzebujesz więc jednej piątki na każdy proces roboczy, aby wysłać dane, i jednej piątki na proces główny, aby odbierać rzeczy od robotników.OŚWIADCZENIE Napisałem ten skrypt z góry głowy. Może mieć pewne problemy ze składnią.
źródło
find . -type f | while read i
zamiastfor i in $(find . -type f)
.W przypadku GNU Parallel rozmiar bloku można ustawić za pomocą opcji --block. Wymaga to jednak wystarczającej ilości pamięci, aby utrzymać 1 blok w pamięci dla każdego z uruchomionych procesów.
Rozumiem, że nie jest to dokładnie to, czego szukasz, ale na razie może to być akceptowalne obejście.
Jeśli Twoje zadania trwają średnio w tym samym czasie, możesz użyć mbuffera:
źródło
Spróbuj tego:
mkfifo
dla każdego procesu.Następnie trzymaj
tail -f | myjob
się każdego piątki.Na przykład konfigurowanie pracowników (procesy Myjob)
W zależności od aplikacji (myjob) możesz używać zadań -s do znalezienia zatrzymanych zadań. W przeciwnym razie wyświetl listę procesów posortowanych według procesora i wybierz ten, który zużywa najmniej zasobów. Of sam raport zadania, np. Ustawiając flagę w systemie plików, gdy chce więcej pracy.
Zakładając, że zadanie zostanie zatrzymane podczas oczekiwania na dane wejściowe, użyj
jobs -sl
na przykład znaleźć numer zatrzymanego zadania i przypisać mu pracęTestowałem to z
Muszę przyznać, że właśnie wymyśliłem so ymmv.
źródło
Naprawdę potrzebny jest do tego jakiś mechanizm kolejki.
Czy możliwe jest, aby zadania odczytywały dane wejściowe z kolejki, takie jak kolejka komunikatów SYSV, a następnie programy działały równolegle po prostu wypychając wartości do kolejki?
Inną możliwością jest użycie katalogów dla kolejki, takich jak to:
pending
mv
pierwszy plik, który widzi w katalogu do katalogu rodzeństwa opending
nazwieinprogress
.pending
źródło
objaśniając odpowiedź @ ash, możesz użyć kolejki komunikatów SYSV do rozpowszechnienia pracy. Jeśli nie chcesz pisać własnego programu w C, istnieje narzędzie o nazwie,
ipcmd
które może pomóc. Oto, co zestawiłem, aby przekazać dane wyjściowefind $DIRECTORY -type f
do$PARALLEL
liczby procesów:Oto przebieg próbny:
źródło
O ile nie można oszacować, jak długo dany plik wejściowy będzie przetwarzany, a procesy robocze nie będą miały możliwości zgłoszenia się do harmonogramu (tak jak ma to miejsce w zwykłych scenariuszach obliczeń równoległych - często przez MPI ), generalnie nie ma szczęścia - albo zapłacić karę niektórym pracownikom przetwarzającym dane wejściowe dłużej niż inni (z powodu nierówności danych wejściowych), albo zapłacić karę odrodzenia jednego nowego procesu dla każdego pliku wejściowego.
źródło
GNU Parallel zmieniło się w ciągu ostatnich 7 lat. Więc dzisiaj może to zrobić:
Ten przykład pokazuje, że procesom 11 i 10 podano więcej bloków niż procesom 4 i 5, ponieważ 4 i 5 czytają wolniej:
źródło