od Podstaw
6 godz. 26 min · Go · Full-stack i Programowanie
Piotr KrzesajW Go wszystko opiera się o typy. Czym one są? Tak zwane typy proste(string, int, float itd.) to tylko początek, interfejsy, struktury i nie tylko. Pokażę Ci jak używać wielu wątków Go i jakie są sposoby komunikacji między nimi, a także opowiem i pokażę na praktycznych przykładach jakie zagrożenia niesie ze sobą wykorzystywanie wielowątkowości.
W Go nie mamy obiektowości znanej z wielu innych języków. Posiada zalążki obiektowości ale sprawia to wielu osobom problemy jak podejść do architektury aplikacji. Nauczę Cię jak podejść do funkcyjności w taki sposób aby wciąż nawet duże aplikacje były łatwo rozwijalne lub co ważniejsze, była możliwość podzielenia ich na mniejsze mikroserwisy gdy zajdzie taka potrzeba.
Wśród programistów można usłyszeć głosy że w Go wielowątkowość jest świetnie rozwiązana i trudno się z tym nie zgodzić ale warto pamiętać że nasze mózgi działają jednowątkowo i często pomijamy zagadnienia takie jak wyścig wątków, deadlock i inne wyzwania, które stawia przed nami praca na dzisiejszych procesorach. Pokażę i wytłumaczę Ci w praktyce większość z nich i jak sobie z nimi radzić i na co uważać. Jeśli nie pracowałeś z językami wielowątkowymi to ta sekcja jest specjalnie dla Ciebie.
Zastanawiałem się wiele razy czy nie istnieje taka technologia w której piszę sobie jeden pliczek i z tego pliku do każdego języka mogę wygenerować sobie klienta i serwer jedną komendą. To jest w wielkim skrócie GRPC, nie musisz się przejmować czy używasz HTTP 1.1/2.0, czy używasz websocketów do transmisji, czy przesyłasz dane w formacie JSON, XML, Protobuf, czy jest moje API kompatybilne wstecz. Tym wszystkim zajmuje się GRPC. Wyjaśnię Ci czym dokładnie jest, dlaczego jest super i wreszcie jak tego używać razem z językiem Go. Napiszemy praktyczny projekt chatu w którym wykorzystamy funkcję server-streaming.
Pisząc aplikację chcemy aby uruchamiała się ona tak samo niezależnie czy uruchamiamy ją na Linuxie, macOS czy na Windowsie i z pomocą przychodzi nam Docker. Pokażę Ci jak z gotowej aplikacji napisanej w Go stworzyć obraz Dockerowy aby móc go uruchamiać na swoim komputerze bądź serwerze. Pokażę Ci również jak nasz obraz Dockerowy połączyć z bazą danych za pomocą Docker Compose aby móc cieszyć się działającą aplikacją uruchamianą jedną komendą.
Kurs Go nie mógłby obejść się bez serwera HTTP stworzonego tylko z pomocą biblioteki wbudowanej w język Go. Dokładnie tak, nie musisz instalować nic poza językiem i już możesz tworzyć serwery co jest świetną wiadomością. Następnie pokażę Ci popularną bibliotekę Gin do tworzenia serwerów. Dzięki temu zobaczysz różnice i ocenisz czy warto zostać przy wbudowanej bibliotece czy może używać zewnętrznych.
Jak w każdym języku serwerowym tak i w Go możemy się podłączyć pod bazę danych. Krok po kroku wyjaśnię Ci jak to zrobić prosto i przyjemnie używać baz SQL, które od dziesiątek lat cieszą się niezwykłą popularnością. Migracje, zapytania czy dbanie o połączenie to nie będzie dla Ciebie nic trudnego.
Ten Kurs powstał z myślą o osobach, które chciałyby poszerzyć swoją wiedzę o język Go. Zakłada on że posiadasz już wiedzę z minimum jednego innego języka programowania i wiesz w jaki sposób działa komunikacja po protokole HTTP. Możesz też znać Go i chcieć zobaczyć jak dzielić programy na paczki tak aby były łatwo rozwijalne w przyszłości.
Polak słynie ze swojej wielu wątpliwości i
sposobu w jak łatwy sposób można taką wielką wątpliwość zaimplementowane tutaj.
Oczywiście to pokażę pokażę ci jak komunikować się między wątkami.
Ale chciałbym też zaznaczyć i pokazać Ci
wyzwania i problemy które to powoduje aby uruchomić coś na osobnym wątku.
Zacznijmy od wypisania prostej rzeczy
musimy sobie żeby uruchomić coś na osobnym wątku musimy stworzyć osobną
funkcję żeby stworzyć funkcję oczywiście wiemy jak to zrobić piszemy Frank i plan.
Oczywiście nazwa funkcji może być dowolna i chcemy w tej funkcji dopisać coś.
A więc wpisujemy.
To jest.
No i uruchamiamy to.
Jeśli sobie to uruchomimy to wiemy dokładnie co się stanie.
Zostanie to wypisane w konsoli.
Natomiast jeśli chcemy uruchomić to na
osobnym wątku wystarczy w slangu dopisać słówko kluczowego wsparcia i gotowe.
Jeśli to uruchomimy to zobaczymy że nic się w konsoli nie wypisze.
I tutaj mamy pierwszy problem wiele wątpliwości.
Programiści myślą liniowo i ogólnie ludzie
myślą liniowo a tutaj niestety dzieją się dwie rzeczy.
W tym samym czasie
mamy pierwszy wątek główny funkcji Man jest to możemy nazwać
Machine Machine to nazywa ten główny wątek kiedy on zostanie.
Nie będzie miał już nic do roboty to program zostanie zakończony dlatego że
jeśli wychodzimy z funkcji kończymy program więc jeśli uruchamiamy na
osobnym wątku wypisanie tej rzeczy to jak to jest wrzucane na osobny wątek.
A tutaj dalej mogą się dziać różne rzeczy czyli jeśli tutaj piszemy Print Line.
I to uruchomimy.
Oczywiście to wciąż się wywoła ale wciąż
nie widzimy tego w jaki sposób możemy to zrobić na kilka różnych sposobów.
Pierwszym sposobem to jest po prostu zatrzymanie głównego wątku żeby to zrobić
musimy użyć oczywiście biblioteki standardowej Time.
This flip.
I Time przejmuje Time czyli Time Second razy np.
3 czyli w tym momencie wątek główny poczeka trzy sekundy.
Jeśli to uruchomimy
to wtedy wywoła nam się funkcja Hello world czyli to się nam pisze i wypisze nam
się też to co jest osobnym osobnym wątku wywołane dlatego że zanim
główny wątek się zakończył to ten wątek zdążył się już uruchomić
bo nie do końca wiemy kiedy dany wątek zostanie uruchomiony.
Jak zrobić tak żeby nie używać tego Time Sleep.
Tak po prostu wystarczy użyć do tego kanału.
Czym są kanały.
Kanały to jest coś co realizuje kilka
wątków i powoduje że jeden wątek czeka na wiadomość wysłane przez kanał.
Do drugiego wątku w jaki sposób to zrobić musimy sobie stworzyć ten kanał czyli
służby Competition kanał czyli Channel czyli Connection
Channel stwórzmy go żeby go stworzyć musimy użyć kluczowego MAK.
Następnie używamy słówka kluczowego
dużo słów kluczowych które trzeba zapamiętać i musimy nadać typ kanału czyli
jaką wiadomość chcemy w nim przesłać chcemy w nim przesłać informację że już
zostało to wykonane więc chcemy użyć tutaj typu bulli czyli po prostu wyślemy tam do
tego kanału przekaz żeby wysłać coś do kanału musimy go przekazać jako parametr
do funkcji czyli jako parametr tweet przekazujemy Competition tam.
I jest to kanał który jest bolidem.
I teraz Google rzeczywiście nas prosi
żebyśmy przekazali ten parametr przy wywołaniu funkcji przekazujemy go i
po wpisaniu do konsoli chcemy wysłać do kanału informację
czyli używamy strzałki która jest złożona z w tym przypadku znaku
mniejszości i pauzy i wysyłamy tam tylko wysyłamy że hej skończyłem.
I w tym przypadku żeby poczekać na to aż.
To skończy swoje działanie.
Załóżmy że w międzyczasie chcemy wypisać Hello world i chcemy poczekać żeby
poczekać musimy zacząć od szczotki i Competition.
I w tym przypadku
go w tym miejscu się zatrzyma i poczeka aż ten wątek skończy swoje
działanie a następnie poczeka trzy sekundy co nie jest w tym momencie potrzebne
uruchomimy ten kod i zobaczmy czy zadziała i po uruchomieniu zostanie wypisany Hello
world i następnie zostanie wypisana ta wiadomość.
I tak jeśli zmienimy ten kanał i poczekamy w tym miejscu
i uruchomimy to co zostanie to wypisane w odwrotnej kolejności.
Tutaj dochodzimy do kolejnego problemu.
Wiele wątpliwości które są te bloki The
Block to jest sytuacja kiedy jeden wątek czeka aż drugi wątek skończy swoją pracę
ale ten drugi wątek mimo skończonej swojej pracy bądź nigdy jej nie skończy.
Mamy taką sytuację pocztową każdy wątek na coś czeka i żaden nic nie robi.
Możemy symulować taką sytuację w bardzo
prosty sposób kiedy wywołuje metodę przekazujemy to kanał po prostu ten kanał
nie zwróci nigdy wartości czyli nigdy nie skończy swojej pracy.
Zobaczmy co się stanie
jak sobie to uruchomimy w trybie dodatkowym to nic nam nie wyskoczy.
Natomiast jeśli uruchomimy to jako.
Nie trzeba głowy tylko to z trybu normalnego czyli Run Run
to zobaczymy że wyskoczy nam All Things The Block.
Oznacza to że wszystkiego rutyny śpiączki czekają na coś i gola kto wygrywa
więc jeden problem powiedzmy że mamy rozwiązany i zostanie aplikacja zabita.
Natomiast nie zawsze to działa
bowiem tego nie zobaczymy więc bardzo często zdarza się że dopiero po
uruchomieniu i po testowaniu aplikacji tak naprawdę dowiadujemy się czy popełniliśmy
jakiś błąd jeśli chodzi o wyjątkowość bądź i to jest największy problem.
Kolejnym problemem jest tzw.
afgańską gdyż to jest sytuacja w której
może po prostu pokażę na przykładzie mamy zmienną która jest indeks jest ona o
wartości 10 i mamy tutaj jedną funkcję indeks.
I załóżmy że ona jest tworem nie skończonym.
I ona za każdym razem podaje do indeksu 1 i mamy drugą funkcję która jest indeks
i ona też jest tworem który nigdy się nie skończy i my chcemy wypisać.
Ten indeks ale Pobierz go tutaj czyli za każdym razem będziemy pobierali indeks.
Print to będzie nasz indeks.
Będziemy go wypisywać i funkcji uruchomimy.
Tylko indeks na osobnym wątku.
Indeks i żeby nie zakończyć działania
programu odczytywanie z na głównym wątku temacie W tym samym momencie wpisujemy coś
do zmiennej i odczytuje z niej zobaczmy co się stanie jeśli uruchomimy taki kod.
Zobaczymy że oczywiście muszę go zatrzymać może będzie to
że odczytywanie zmiennej Zmienna cały czas pokazuje że jest o wartości 10.
Dlaczego. Dlatego że podczas odczytywania jest
zablokowany zapis przez co nie możemy zapisywać w jaki sposób to zrobić.
I tutaj musimy poczekać aż myślę o tym.
Jeśli.
Odwiedził.
Tak więc żeby to zrobić musimy zsynchronizowane w jakiś sposób wątki żeby
to zrobić musimy użyć biblioteki Atomic Sing.
Jeśli chcemy odczytać coś musimy zrobić tomik LOT
kropka lot i tu będzie int 64 chcemy odczytać coś z wartości indeksu.
Ale indeks musi to być
indeks i to musi być wskaźnik do indeksu więc używamy tego jako
wskaźnik z 64 czyli dobrze czyli musimy tutaj nadać mu typ %64.
I teraz już nie ma problemu 30 usunac to
to zadziała nie zadziała wiec musi to być wskaźnik.
Natomiast jeśli zapisujemy coś.
To znowu musimy użyć tutaj funkcji Atomic
AT i 64 64 i podać adres do zmiennej czyli
indeks i wartość czyli indeks plus 1.
I w tym momencie jeśli to uruchomimy.
To małe minus 1 minus 1 minus 1.
I dlaczego to się tak dzieje.
Dzieje się tak dlatego
że podczas dodawania linka 64 w paczce upominków
nie możemy używać indeks plus 1 tylko dodajemy do obecnej zmiany dodajemy coś
czyli dodajemy w tym momencie 1 do tego jeśli to uruchomimy
zmienna nam bardzo szybko rośnie oczywiście na dwóch osobnych wątkach.
Czyli to paczka tomik czeka aż zostanie odczytana dana zmienna przez jeden wątek
i blokuje drugi wątek przed zapisem danych i dopiero po odczycie następuje zapis.
Jeśli w tym samym momencie ktoś czeka na
odczyt to musi poczekać aż ten zapis się skończy i dopiero może odczytać.
Są różne strategie i różne metody synchronizacji wątków.
I to jest jeden z nich ten właśnie pokazuje
możliwe że w dalszych częściach kursu pokażę ci też również i inne metody i w
tej reakcji to wszystko zapraszam do kolejnych.