Właściwe użycie wątków i procesów

0

Witam

Proszę wybaczcie niedoskonałość opisu i grafiki – dopiero zaczynam swoją przygodę z programowaniem 

Tworzę program, który ma za zadanie:

  • odbiór danych z 3 urządzeń (sensorów) podłączonych po TCP/IP,
  • przeprowadzenie odpowiednich obliczeń
  • i wysłanie wyniku po TCP/IP.

Sensory mają bardzo krótki czas reakcji (co ok. 10ms wysyłane są dane) stąd pomysł aby pobierać z nich dane za pomocą krótkich programów uruchomionych jako oddzielne wątki.
Programy te by tylko odbierały dane, sprawdzały ich poprawność i zapisywały do zmiennej (powiedzmy z urządzenia A do zmiennej A, z urządzenia B do zmiennej B i z urządzania C do zmiennej C)

Z kolei obliczenia byłyby dokonywane w dwóch osobnych procesach (myślałem o skorzystaniu z bibilioteki multiprocessing).

W pierwszym procesie (Proces I) pobierana byłaby najnowsza zmienna C i byłyby dokonywane
stosowane obleczenia na tej zmiennej. Następnie zmienna ta byłaby gotowa do wysłania a Proces I gotów do zamknięcia.

W drugim procesie (Proces II) byłaby pobierana najnowsza zmienna B i dokonywane byłby obliczenia na tej zmiennej.
Następnie pobierana by była zmienna C z Procesu I i dane byłby ze sobą łączone.
W kolejnym kroku dane byłby wysyłane do programu głównego

Program główny pobrałby dane z Procesu II i wysłał polecenie do wątku obsługującego urządzenie A o przesłanie danych.
Po otrzymaniu danych od urządzenia A dane byłby ze sobą łączone i wysłane do wątku obsługującego urządzenie D.
Wątek ten wysyłałby dane dalej w świat po TCP/IP

Proszę Was o odpowiedź na poniższe pytania:

  1. Czy taka koncepcja ma sens i czy zastosowanie wątków oraz procesów w takiej formie jest rozsądne?
  2. Czy jesteśmy w stanie z wątku przesłać dane bezpośrednio do procesu (np. z wątku Urządzenie C do Proces I)?
  3. W jaki sposób najlepiej przesyłać dane (poprzez Queue / Primitives np. Lock / Wiadomości po Socket/Pipe) między:
  • jednym a drugim wątkiem
  • programem głównym a procesem
  • procesem a którymś z wątków (jeśli w ogóle to możliwe)

z góry dziękuję za pomoc i każdą sugestię
Pozdrawiam

0

@Zeej: dzięki za odp.
jestem jeszcze na podstawowym poziomie, czytałem o bibliotece asyncore i event loop ale miałem nadzieję że uda mi się to obsłużyć za pomocą wątków bo te już wykorzystywałem we wcześniejszych "programach" - stąd taki pomysł :) poczytam o async i RabbitMQ zobaczę czy uda mi się to zrozumieć/zastosować

0

TL; DR
Moim zdaniem ta architektura jest niepotrzebnie zbyt złożona. W ogólności odradzałbym też mieszanie wątków i procesów pythonowych.

Czy taka koncepcja ma sens i czy zastosowanie wątków oraz procesów w takiej formie jest rozsądne?

Na początku odpowiedziałbym sobie na pytanie, czy w ogóle potrzebujesz wątków. Domyślam się, że wiesz, iż w Pythonie jest coś takiego jest GIL (Global Interpreter Lock). Istnienie GIL-a wynika z samego działania pythonowego Garbage Collectora. To co jest istotne to fakt, że GIL nie pozwala uruchamiać kilku wątków na wielu procesorach. Implikuje to, że moduł threading w Pythonie zawsze będzie wykonywał kod tylko na jednym procesorze. Można więc zapytać, jaka jest korzyść z tego modułu w ogóle? Okazuje się, że w przypadku tzw. operacji wejścia-wyjścia (I/O) większość programów spędza czas na oczekiwaniu na przyjście danych. Na przykład wysyłamy żądanie http i czekamy aż strona nam odpowie. Samo wysłanie żądania jest relatywnie dużo krótsze.

System operacyjny komputera, załóżmy z jednym procesorem (chyba już rzadko spotykane), wydaje się wykonywać wiele zadań równolegle. W rzeczywistości tak nie jest. W danym momencie czasu t procesor wykonuje tylko jedną operację na raz. Przykładowo renderuje okno z przeglądarką lub odtwarza muzykę. Wszystkie tego typu zadania są dzielone na kawałki i wykonywane naprzemiennie w bardzo krótkim czasie dt. W przeciwnym razie, gdyby procesor w pętli renderował okno przeglądarki cały czas, to nie moglibyśmy słuchać muzyki. Czas dt jest bardzo krótki, w sieci znalazłem dość duży rozrzut tej wartości od nanosekund po kilkadziesiąt milisekund. Czyli po czasie dt zapisywany jest bieżący stan renderowania okna i procesor przełącza się na odtworzenie fragmentu piosenki. Operacja przeskakiwania nazywa się przełączaniem kontekstu (context switch). Jeśli przełączanie kontekstu rzeczywiście następuje po czasie ~10 ms, to użycie wątków niewiele tu pomoże. Chyba najprościej to sprawdzić, pobierając zapytania z pomocą wątków i bez, i porównując czasy.

Czy jesteśmy w stanie z wątku przesłać dane bezpośrednio do procesu

W teorii tak, przy czym ja tego nigdy nie próbowałem, więc potwierdzić nie mogę. Tworząc nowe procesy za pomocą modułu multiprocessing uruchamiane są kolejne interpretery Pythona. Każdy z nich posiada własny GIL. Z mojego punktu widzenia nic nie stoi na przeszkodzie, aby w obrębie procesu uruchomić wątki. Wszak "główny program" zostaje zawsze uruchomiony w nadrzędnym procesie Pythona. Aby współdzielić dane pomiędzy pythonowymi procesami wykorzystuje się serializację. To implikuje, że pomiędzy procesami można przekazywać obiekty picklowalne. Przykładowo nie da się przekazać wyrażenia lambda.

W jaki sposób najlepiej przesyłać dane między jednym a drugim wątkiem?

W przypadku wątków możesz użyć zmiennych globalnych zdefiniowanych w wątku nadrzędnym (głównym) i wykorzystać je w pochodnych wątkach. Aby uniknąć zjawiska race condition powinieneś także obsłużyć zamek. Lepszym rozwiązaniem będzie jednak wykorzystanie kolejki Queue, które ten mechanizm posiada. Można również definiować swoje własne typy, ważne by panować na takimi rzeczami jak wspomniany race condition lub deadlock.

W jaki sposób najlepiej przesyłać dane między programem głównym a procesem?

Jak pisałem wyżej, program główny to też proces, wykorzystać trzeba serializację. Jeśli używasz starszych wersji Pythona, znajdziesz coś takiego jak SyncManager, który udostępnia obiekty typu AutoProxy (obiekty podlegające serializacji). Od wersji 3.8 możliwe jest używanie SharedMemory, co może być pomocne, jeśli operujesz na dużych zbiorach, np. spore tablice z NumPy.

W jaki sposób najlepiej przesyłać dane między procesem a którymś z wątków (jeśli w ogóle to możliwe)?

To musiałbyś zestawić to, co napisałem w dwóch poprzednich punktach.


Podsumowując, architektura jest zbyt zawiła. Nie mieszałbym procesów i wątków w jednym programie, póki nie miałbym wystarczająco dobrych argumentów, by to robić. Na pierwszy rzut oka ograniczyłbym się do multiprocessingu, chyba że faktycznie wątki znacznie przyspieszają pobieranie. Ale to trzeba sprawdzić, bo brakuje mi tu wiedzy. Co do multiprocessingu to też pewności nie mam. Być może te obliczenia które wykonujesz nie są w ogóle zoptymalizowane i niepotrzebnie spawnujesz dodatkowe procesy. Być może z wykorzystaniem modułu numpy nie potrzebowałbyś w ogóle współbieżności.

1 użytkowników online, w tym zalogowanych: 0, gości: 1