Przechodzimy znowu do Pythona po dłuższej nieobecności! Ostatnim razem napisałem Wam co nieco na temat tworzenia wątków i wykorzystywania ich do wykonywania podanej funkcji. Oto przed Wami druga część programowania współbieżnego, czyli rzut okiem na pakiet "concurrent" w Pythonie! Dowiecie się czym się różni programowanie przy pomocy "concurrent" od poznanego modułu "threading" i co można dzięki temu uzyskać.

PAKIET "CONCURRENT" RÓWNIEŻ POZWALA PROGRAMOWAĆ WSPÓŁBIEŻNOŚĆ

Przestrzegam Was przed słowem "pakiet"! Wiecie już doskonale czym to się różni od modułu, aczkolwiek muszę Wam napisać na starcie: "concurrent" posiada w sobie tylko jeden moduł jaki można zaimportować. Nazywa się on "concurrent.futures" i to on w gruncie rzeczy będzie tutaj rozpatrywany. Postanowiłem jednak napisać w nagłówku o pakiecie z racji tego, że w przyszłości mogą pojawić się jakieś dodatkowe moduły i nie trzeba będzie modyfikować odnośnika URL do tego artykułu.

TWORZENIE WĄTKU PRZY POMOCY "CONCURRENT.FUTURES"

Zaczynamy od importu modułu. Bęc:

import concurrent.futures

Tym sposobem dostajemy do dyspozycji klasę "ThreadPoolExecutor" jaką posiada pakiet "concurrent" w Pythonie dzięki której zrealizujemy sobie programowanie współbieżne. W przeciwieństwie jednak do poprzednika, ten obiekt nie służy do wprowadzania instrukcji osobnemu wątkowi do wykonania. On pełni funkcję menadżera. Wszystko wyjaśni się na poniższym przykładzie.

Przywróćmy sobie tę samą funkcję z poprzedniego artykułu:

def square(n):
    return n**2

Załóżmy, że chcemy sobie zrobić wątek, który przyjmuje funkcję zwracającą wartość, ale wymaga ona podania parametru formalnego. Tworzymy sobie zmienną, a po znaku przypisania wywołujemy sobie metodę "submit", w taki oto sposób:

t = [instancja klasy "ThreadPoolExecutor"].submit([nazwa funkcji], [parametr 1], ...)

Już wyjaśniam co się tu odbywa. "submit" jako parametry przyjmuje najpierw nazwę funkcji (samą nazwę bez nawiasów), a każdy następny parametr jest parametrem wprowadzanym do funkcji, którą się podało. Mamy tu do czynienia ze zmienną liczbą parametrów, gdyż nie ma żadnego określonego limitu wprowadzanych argumentów. Zatem, gdy tradycyjne wywołanie funkcji wygląda tak:

x = square(2)

pakiet "concurrent" w Pythonie nakazuje, aby się je wpisywało tak:

submit(square, 2)

Podajecie tyle samo parametrów ile przyjmuje funkcja. Trzy, pięć, piętnaście, nieważne ile ona posiada. Nie powinniście mieć problemów z opanowaniem tej okrężnej drogi. Dla wszystkich lubiących eksperymenty. W grę nie wchodzi zamiana parametrów miejscami, tak jak można to zrobić przy tradycyjnym wywołaniu.

ZWROT WARTOŚCI FUNKCJI

A co ze zwracaniem? Wątek nie podejmie się automatycznie próby wypisania rezultatu. Trzeba go "popchnąć" korzystając z metody "result". To jest tak, jakbyście napisali samo "return", ale tak jakby na zewnątrz podanej przez Was funkcji. To jest tylko skrót myślowy więc proszę nie brać tego na serio. Samo "result" niczego nie da i z tego powodu dobrą praktyką jest połączenie tej funkcji z funkcją "print", aby ujrzeć wynik zwrócony przez funkcję "przesiadującą" w wątku.

Metoda "result" klasy "ThreadPoolExecutor" w Pythonie (pakiet "concurrent")

Metoda "result" zwraca wynik uzyskany w wyniku zwrócenia wartości przez funkcję wywołaną podczas działania wątku. Najlepiej ją połączyć z funkcją "print", aby ukazała się wartość na wyjściu.

Pamiętajcie, że pakiet "concurrent" w Pythonie obsługuje zarówno funkcje zwracające wartość, jak i te niezwracające wartości. Przy tej drugiej opcji, "result" nie będzie potrzebne, bo nie dojdzie do zwrócenia jakiejkolwiek wartości.

CZY "CONCURRENT" DAJE COŚ, CZEGO "THREADING" NIE MOŻE?

Tak. W poprzednim artykule wspomniałem o tym samym punkcie, a mianowicie że "threading" nie udostępnia nam drogi zwracania wartości przez funkcję (jeśli zwraca jakąkolwiek). Jeżeli interesuje Was programowanie współbieżne, a w założeniach projektowych macie podpunkt, że musi dojść do zwracania wartości, zostaje Wam tylko pakiet "concurrent".

Jest jeszcze coś. Pakiet "concurrent" w Pythonie umożliwia tworzenie nie tylko samych wątków, ale także nowych procesów! To jest drugi podpunkt dlaczego opłaca się skorzystać z "concurrent" niż z "threading"!


To już wszystko na ten temat. Wniosek jest prosty: jeżeli wątek otrzymuje funkcję, która ma zwrócić wynik, korzystacie z "concurrent". W przeciwnym wypadku, macie do dyspozycji obie możliwości.

PODOBNE ARTYKUŁY