Wierzę, że społeczność Erlang nie jest zazdrosna o Node.js, ponieważ natywnie blokuje operacje we / wy i ma sposoby na łatwe skalowanie wdrożeń na więcej niż jednym procesorze (coś, co nie jest nawet wbudowane w Node.js). Więcej informacji na http://journal.dedasys.com/2010/04/29/erlang-vs-node-js i Node.js lub Erlang
Co z Haskellem? Czy Haskell może zapewnić niektóre korzyści z Node.js, a mianowicie czyste rozwiązanie, aby uniknąć blokowania I / O bez konieczności programowania wielowątkowego?
Istnieje wiele rzeczy, które są atrakcyjne w Node.js
- Zdarzenia: Brak manipulacji wątkiem, programista zapewnia tylko wywołania zwrotne (jak w środowisku Snap)
- Oddzwanianie jest gwarantowane w jednym wątku: nie jest możliwy żaden wyścig.
- Ładny i prosty interfejs API przyjazny dla UNIX. Bonus: doskonała obsługa HTTP. DNS również dostępny.
- Każde wejście / wyjście jest domyślnie asynchroniczne. Ułatwia to unikanie zamków. Jednak zbyt duże przetwarzanie procesora w wywołaniu zwrotnym wpłynie na inne połączenia (w tym przypadku zadanie powinno zostać podzielone na mniejsze podzadania i ponownie zaplanowane).
- Ten sam język dla klienta i serwera. (Jednak nie widzę w tym zbyt dużej wartości. JQuery i Node.js współużytkują model programowania zdarzeń, ale reszta jest zupełnie inna. Po prostu nie widzę, w jaki sposób współdzielenie kodu między serwerem a klientem może przydać się w praktyce).
- Wszystko to zapakowane w jeden produkt.
Odpowiedzi:
Ok, po obejrzeniu trochę prezentacji node.js , na którą skierował mnie @gawi, mogę powiedzieć nieco więcej o tym, jak Haskell wypada w porównaniu z node.js. W prezentacji Ryan opisuje niektóre zalety zielonych nici, ale następnie mówi, że nie uważa braku abstrakcji nici za wadę. Nie zgadzam się z jego stanowiskiem, szczególnie w kontekście Haskella: Myślę, że abstrakcje dostarczane przez wątki są niezbędne, aby kod serwera był łatwiejszy do poprawienia i bardziej niezawodny. W szczególności:
użycie jednego wątku na połączenie pozwala napisać kod, który wyraża komunikację z jednym klientem, zamiast pisania kodu, który obsługuje wszystkich klientów jednocześnie. Pomyśl o tym w ten sposób: serwer, który obsługuje wielu klientów z wątkami, wygląda prawie tak samo, jak ten, który obsługuje jednego klienta; główna różnica polega na tym, że jest
fork
gdzieś w tym pierwszym. Jeśli implementowany protokół jest w ogóle skomplikowany, zarządzanie maszyną stanową dla wielu klientów jednocześnie staje się dość trudne, podczas gdy wątki pozwalają po prostu skryptować komunikację z jednym klientem. Kod jest łatwiejszy do poprawnego, łatwiejszy do zrozumienia i utrzymania.wywołania zwrotne w jednym wątku systemu operacyjnego to wielozadaniowość kooperacyjna, w przeciwieństwie do wielozadaniowości zapobiegawczej, którą uzyskuje się dzięki wątkom. Główną wadą współpracy wielozadaniowej jest to, że programista jest odpowiedzialny za to, aby nie dopuścić do głodu. Traci modułowość: popełnij błąd w jednym miejscu i może zepsuć cały system. To naprawdę coś, o co nie musisz się martwić, a zapobieganie jest prostym rozwiązaniem. Ponadto komunikacja między wywołaniami zwrotnymi nie jest możliwa (spowodowałoby to zakleszczenie).
współbieżność nie jest trudna w Haskell, ponieważ większość kodu jest czysta, a więc z założenia bezpieczna dla wątków. Istnieją proste prymitywy komunikacyjne. W Haskell o wiele trudniej jest strzelać sobie w stopę niż w język o nieograniczonych skutkach ubocznych.
źródło
Tak, w rzeczywistości wydarzenia i wątki są zunifikowane w Haskell.
Wątki są faktycznie implementowane pod względem zdarzeń i działają na wielu rdzeniach, z płynną migracją wątków, z udokumentowaną wydajnością i aplikacjami.
Np. Dla
Jednoczesne kolekcje nbody na 32 rdzeniach
W Haskell masz zarówno wydarzenia, jak i wątki, a wszystko to pod maską.
Przeczytaj artykuł opisujący wdrożenie.
źródło
Po pierwsze, nie uważam, że node.js robi właściwą rzecz, ujawniając wszystkie te wywołania zwrotne. W końcu piszesz swój program w CPS (styl przekazywania kontynuacji) i myślę, że to kompilator powinien wykonać tę transformację.
Mając to na uwadze, możesz pisać w stylu asynchronicznym, jeśli chcesz, ale robiąc to, stracisz możliwość pisania w efektywnym stylu synchronicznym, z jednym wątkiem na żądanie. Haskell jest absurdalnie wydajny w kodzie synchronicznym, szczególnie w porównaniu do innych języków. Wszystko pod spodem.
Nadal możesz mieć warunki wyścigu w node.js, ale jest to trudniejsze.
Każde żądanie jest w swoim wątku. Kiedy piszesz kod, który musi komunikować się z innymi wątkami, bardzo łatwo jest zapewnić bezpieczeństwo wątków dzięki prymitywom współbieżności haskell.
Rzuć okiem na hakerów i przekonaj się sam.
Nie masz takich problemów, ghc rozdzieli Twoją pracę między prawdziwe wątki systemu operacyjnego.
Haskell nie może tutaj wygrać ... prawda? Pomyśl jeszcze raz, http://www.haskell.org/haskellwiki/Haskell_in_web_browser .
Pobierz ghc, odpal cabal. Istnieje pakiet na każdą potrzebę.
źródło
Osobiście uważam Node.js i programowanie z wywołaniami zwrotnymi za niepotrzebnie niskopoziomowe i trochę nienaturalne. Po co programować za pomocą wywołań zwrotnych, skoro dobry czas działania, taki jak ten w GHC, może obsługiwać wywołania zwrotne i robić to całkiem skutecznie?
W międzyczasie środowisko uruchomieniowe GHC uległo znacznej poprawie: zawiera teraz „nowego nowego menedżera IO” o nazwie MIO, w którym „M” oznacza, jak sądzę, wielordzeniowy. Opiera się na fundamencie istniejącego menedżera IO, a jego głównym celem jest przezwyciężenie przyczyny obniżenia wydajności rdzeni 4+. Liczby wydajności przedstawione w tym artykule są imponujące. Zobacz siebie:
I:
Mio dostało się do wydania GHC 7.8.1. Osobiście uważam to za duży krok naprzód w wydajności Haskell. Bardzo interesujące byłoby porównanie wydajności istniejących aplikacji internetowych skompilowanych przez poprzednią wersję GHC i 7.8.1.
źródło
Zdarzenia IMHO są dobre, ale programowanie za pomocą wywołań zwrotnych nie jest.
Większość problemów, które wyróżniają kodowanie i debugowanie aplikacji internetowych, pochodzi z tego, co czyni je skalowalnymi i elastycznymi. Najważniejszy, bezpaństwowy charakter HTTP. Zwiększa to nawigowalność, ale narzuca odwrócenie kontroli, gdy element IO (w tym przypadku serwer WWW) wywołuje różne procedury obsługi w kodzie aplikacji. Ten model zdarzeń - lub dokładniej mówiąc - model zwrotny - jest koszmarem, ponieważ wywołania zwrotne nie dzielą zmiennych zakresów, a intuicyjny widok nawigacji został utracony. Bardzo trudno jest zapobiec wszystkim możliwym zmianom stanu, gdy użytkownik porusza się w przód iw tył, między innymi problemami.
Można powiedzieć, że problemy są podobne do programowania GUI, w którym model zdarzeń działa dobrze, ale GUI nie mają nawigacji ani przycisku powrotu. To zwielokrotnia możliwe przejścia stanu w aplikacjach internetowych. Rezultatem próby rozwiązania tego problemu są ciężkie frameworki o skomplikowanych konfiguracjach, mnóstwo wszechobecnych magicznych identyfikatorów bez kwestionowania źródła problemu: model wywołania zwrotnego i nieodłączny brak współdzielenia zmiennych zakresów oraz brak sekwencjonowania, więc sekwencja musi być skonstruowane przez połączenie identyfikatorów.
Istnieją frameworki oparte na ramach, takich jak ocsigen (ocaml) nadmorski (smalltalk) WASH (przerwany, Haskell) i mflow (Haskell), które rozwiązują problem zarządzania stanem przy jednoczesnym zachowaniu możliwości nawigacji i pełnej REST. w tych ramach programista może wyrazić nawigację jako imperatywną sekwencję, w której program wysyła strony i czeka na odpowiedzi w jednym wątku, zmienne są w zasięgu, a przycisk Wstecz działa automatycznie. To z natury tworzy krótszy, bezpieczniejszy i bardziej czytelny kod, w którym nawigacja jest wyraźnie widoczna dla programisty. (uczciwe ostrzeżenie: Jestem programistą mflow)
źródło
Pytanie jest dość śmieszne, ponieważ 1) Haskell rozwiązał już ten problem w znacznie lepszy sposób i 2) w mniej więcej taki sam sposób, jak Erlang. Oto punkt odniesienia dla węzła: http://www.yesodweb.com/blog/2011/03/preliminary-warp-cross-language-benchmarks
Daj Haskellowi 4 rdzenie, a on może wykonać 100 000 (prostych) żądań na sekundę w jednej aplikacji. Węzeł nie może zrobić tak wiele i nie może skalować pojedynczej aplikacji między rdzeniami. I nie musisz nic robić, aby to czerpać, ponieważ środowisko uruchomieniowe Haskell nie blokuje. Jedynym innym (stosunkowo powszechnym) językiem, który ma nieblokujące się we / wy wbudowane w środowisko wykonawcze, jest Erlang.
źródło
pm2 -i max path/to/app.js
automatycznie skaluje się do optymalnej liczby instancji w oparciu o dostępne rdzenie. Dodatkowo, Węzeł domyślnie również nie blokuje.Tak jak nodejs upuścił libev, tak samo Snap Haskell Web Framework upuścił libev .
źródło