Wpis z mikrobloga

via Wykop Mobilny (Android)
  • 2
Tak się zastanawiałem ostatnio, dlaczego tak mało popularnych języków programowania oferuje tzw. green threads (lub virtual threads). Wydaje mi się, że na razie sensowne green threads są jedynie w #golang i mają być wprowadzone w #java 19. Wszystkie inne mainstreamowe języki mają jakieś async/awaity albo courutines (albo nawet tego nie mają jak Java do tej pory), żeby optymalnie wykorzystywać wątki procesora. Te rozwiązania są oczywiście bardzo dobre, ale wydają się po prostu gorsze w wielu wypadkach od green threads (np trzeba używać nieblokującego i/o). Jak myślicie, jaka jest przyczyna tych wyborów?
#programowanie
  • 9
@przyjaciel_golomb: Przede wszystkim są trudne do zaimplementowania, bo wymagają przejrzenia i migracji kodu, który "działał pod spodem" w trybie blokującym.

W przypadku Javy będzie to między innymi wszystko co mieliśmy w obsłudze I/O czyli pakiety java.io i java.nio - a co nawet 25+ lat temu ze względów wydajności zostało napisane w natywnym C/C++. No i trzeba to zrobić tak, żeby zachować kompatybilność wsteczną dla wszystkiego co na podstawie tych API zostało
@BenGurion: poniekąd prawda, że można nieźle nabałaganić + trzeba umiejętnie zbierać dane (async/await jest tu prostsze, tak mnie się wydaje). Ale async/await z kolei wymusza odpowiednie sygnowanie takich funkcji (mówię o Rust i Python teraz), to dobrze lub źle - zależy od kontekstu, bo czasem chcesz coś prostego sprawdzić lub użyć coś nie async/await, a masz same takie funkcje w projekcie i cały ciąg sygnatur funkcji trzeba pozmieniać lub stosować jakieś
@przyjaciel_golomb: Green threads to odpowiednik goto w językach strukturalnych. Są bardzo niskopoziomowe. Nadal są to wątki, programuje się je jak wątki, mogą się zdeadlockować jak wątki albo zrobić data race jak wątki, więc w sumie mają wszystkie wady wątków, z wyjątkiem tej jednej, że green threads są trochę lżejsze pamięciowo.

Natomiast async/await umożliwia tzw. structured concurrency. Czyli mogę zrobić sobie coś takiego:

async fn network_request_foo(...) {...}
async fn network_request_bar(...) {...}
let
@devopsiarz: > i cały ciąg sygnatur funkcji trzeba pozmieniać lub stosować jakieś obejścia.

No nie, może w Pythonie tak trzeba, ale generalnie jak masz funkcję blokującą to przerobić ją na async jest balalnie proste, dajesz w spawn_blocking i leci. W drugą stronę zawsze można użyć runtime który działa na bieżącym wątku, więc funkcę async można też wywołać spoza kontekstu async.

Co do artykułu "go considered harmful", gdzie autor porównuje go do
@Krolik: to pokaż kod do playgroundu, gdzie w funkcji async odpalasz funkcję nie-async za pomocą spawn_blocking i to Ci się kompiluje.

Natomiast async/await umożliwia tzw. structured concurrency. Czyli mogę zrobić sobie coś takiego:


To teraz pokaż, jak za pomoca async/await zrobisz coś, co działa przez dłuższy czas (albo do końca trwania programu) i jest różnych momentach wywoływane z różną częstotliwością. Tym samym kodem to pokaż. ( ͡° ͜ʖ ͡
@devopsiarz: Przecież masz przykład w dokumentacji: https://docs.rs/tokio/latest/tokio/task/fn.spawn_blocking.html
Przykłądy w dokumentacji są sprawdzane kompilatorem, więc na pewno się kompiluje.

To teraz pokaż, jak za pomoca async/await zrobisz coś, co działa przez dłuższy czas (albo do końca trwania programu) i jest różnych momentach wywoływane z różną częstotliwością. Tym samym kodem to pokaż. ( ͡° ͜ʖ ͡°)


Jak ma być wywoływane periodycznie przez dłuższy czas, to np. mogę posłużyć się
Przecież w Ruście masz niemalże idealny odpowiednik gorutyn z Go, jako jeden z wielu modeli współbieżnosci do wyboru. Nikt Ci nie broni przecież robić wszędzie tokio::spawn (odpowiednik go w Go) i komunikować korutyny przez channel() (odpowiednik make(chan ...) w Go)


channel to nie jest odpowiednik make chan (skąd to wziąłeś w ogóle?), coś pomyliłeś, konkretnie inicjalizację z typem danych.

Poza tym, w Ruście channele możesz używać z czym chcesz, w tym z
@devopsiarz: lol ten zalinkowany post to w ogóle niezły fikołek, większość programistów na świecie twierdzi że składnia jest prosta i wymienia to jako jedną z jego zalet, prototypuje w tym... ale nie, "składnia skomplikowana" :D

konieczna jest inna składnia o odwrotnej kolejności.

ehe, a w Rust typy definiujemy za nazwą zmiennych, trochę inaczej niż w C/Cpp/javie ;)

W ogóle można by sporo podyskutować z tym postem, ale wolę nie, staram się