Erlang vs Go vs Scala

TurkucPodjadek
TurkucPodjadek
  • Rejestracja:około 8 lat
  • Ostatnio:około 4 lata
  • Postów:607
0

Natrafiłem ostatnio na mały research dotyczący w.w. języków w kwestii skalowalności i szerokorozumianego performance (latency i throughput)

Link: http://www.dcs.gla.ac.uk/~trinder/papers/sac-18.pdf

TL;DR (Conclusion):

We have investigated programming language characteristics that
support the engineering of multicore web servers. Crucially these
languages must be able to support massive concurrency on multicore
machines with low communication and synchronisation overheads.
We have analysed 12 languages considering computation,
coordination, compilation, and popularity, and selected three representative
high-level languages for detailed analysis: Erlang, Go,
and Scala/Akka (Section 2). We have designed three server benchmarks
that analyse key performance characteristics of the languages,
i.e. inter-process communication latency, process creation time, the
maximum number of supported processes, and throughput (Section
3).
A summary of the recommendations based on this small set of
benchmarks is as follows. For a server where minimising message
latency is crucial, Go and Erlang are the best choice (Figure 3).
Interestingly Akka significantly reduces communication latency in
Scala (Figures 3(a) and 3(b)). Scala/Akka are capable of maintaining
the largest number of dormant processes (∼11M processes in
Figure 4(a)), while Erlang performs the best when processes are
short lived and the goal is to ensure minimal spawn time, e.g. Erlang
takes 58s to spawn 9M processes (Section 4.2). In server applications
where up to 100,000 processes are frequently spawned, Erlang and
Go minimise process creation time and scale smoothly (Figure 4(b)).
Experiments with communicating pairs of processes show that Go
provides the highest throughput independent of the number of cores
and the number of process pairs (Figure 5).
Comparing the performance of complete case study servers implemented
in each language would significantly reinforce these
results, and one possibility is an Instant Messaging (IM) benchmark
[4]. It would also be interesting to study the performance
overheads of providing fault tolerance and of recovering from faults,
another key server capability. Finally we could compare the performance
of server languages on distributed memory architectures, e.g.
a cluster of multicores.

Wibowit
  • Rejestracja:prawie 20 lat
  • Ostatnio:8 minut
0

Erlang takes 58s to spawn 9M processes (Section 4.2). In server applications where up to 100,000 processes are frequently spawned, Erlang and Go minimise process creation time and scale smoothly

Co to jest proces w Go i która apka w Go odpala często setki tysięcy procesów? W ogóle kto tak robi?


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
edytowany 1x, ostatnio: Wibowit
siloam
Tak goroutines. Kto tak robi? Duze korpo i koncerny telekomunikacyjne. Średni jest sens programować asynchronicznie stronki firmowe, ale serwery komunikacyjne, gier, serwery reklam itp na tym bardzo korzystają.
TurkucPodjadek
TurkucPodjadek
  • Rejestracja:około 8 lat
  • Ostatnio:około 4 lata
  • Postów:607
0
Wibowit napisał(a):

Erlang takes 58s to spawn 9M processes (Section 4.2). In server applications where up to 100,000 processes are frequently spawned, Erlang and Go minimise process creation time and scale smoothly

Co to jest proces w Go i która apka w Go odpala często setki tysięcy procesów? W ogóle kto tak robi?

Słuszne spostrzeżenie, z tego co widzę (źródła wrzucili tutaj: https://github.com/bbstk/server-languages-benchmarks/) pod pojęciem "procesu" w Go oni rozumują goroutines - to nie są procesy, a wątki w go. Tych wątków można rzeczywiscie spawnować duże ilości ze względu na to, że to nie są wątki 1:1 w OS. Czyli generalnie, pod pojęciem "processes", w tym dokumencie (wnioskuje po kodzie w Go i Erlangu, Scali nie znam) rozumują wątki.

theacid
Jup. W Go można sobie natrzaskać wirtualnych wątków. Miałem dzieś nawet fajną prezentację na ten temat. Jak ktoś by chciał to postaram się odnaleźć.
hauleth
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:10 dni
1

@TurkucPodjadek: w Erlangu to się nazywa procesami, ale nie są to procesy systemowe a Erlangowe właśnie i @Wibowit w Erlangu się je spawnuje na potęgę, przykładowo w Cowboyu (chyba najpopularniejszym serwerze HTTP Erlangowym) każde połączenie przychodzące to jeden niezależny proces, dzięki czemu niezłapany wyjątek nie wyłoży Ci połowy aplikacji a zwyczajnie w świecie ubije jeden proces i po sprawie (bo tak się to najzwyczajniej w Erlangu robi).

Ogólnie kiedyś znalazłem info (teraz nie mogę go ponownie znaleźć), że Akka była inspirowana Erlangiem i autor zwyczajnie chciał przenieść Erlangowe abstrakcje do świata JVMa. Z tego co wiem (nie używałem Akki) podobno wyszło nie najgorzej.

Co do skalowalności to automatyczna klasteryzacja w Erlangu (która jest idiotycznie prosta, bo w większości sprowadza się do net_kernel:connect_node('name@machine') i działa) IMHO wymiata większość tego co jest dostępne. Może sam język nie jest demonem wydajności (JIT bazujący na LLVM jest w trakcie rozwoju), ale dzięki wielu pomysłom (np. GC per proces [wątek jeśli wolicie tą nazwę]) nie traci aż tak bardzo w starciu z obecnymi platformami. Dodatkowo ostatnio pojawia się sporo języków (Elixir, LFE, Joxa), które używają tej samej platformy i oferują "przystępniejszą" składnię niż oryginalna prologowa.


Wibowit
  • Rejestracja:prawie 20 lat
  • Ostatnio:8 minut
0

każde połączenie przychodzące to jeden niezależny proces, dzięki czemu niezłapany wyjątek nie wyłoży Ci połowy aplikacji a zwyczajnie w świecie ubije jeden proces i po sprawie (bo tak się to najzwyczajniej w Erlangu robi).

W każdym typowym JVMowym frameworku wyjątek przy obsłudze żądania nie wywala aplikacji, więc ubijanie pseudo-procesu w tej kwestii nic nie zmienia.

Słuszne spostrzeżenie, z tego co widzę (źródła wrzucili tutaj: https://github.com/bbstk/server-languages-benchmarks/) pod pojęciem "procesu" w Go oni rozumują goroutines - to nie są procesy, a wątki w go.

Goroutines to nie są wątki - goroutines to bardziej async/ await z dodatkową komunikacją.

Kotlin ma coroutines: https://kotlinlang.org/docs/reference/coroutines.html - prawdopodobnie da się na nich uzyskać coś podobnego do Golangowych goroutines. Jak na razie są eksperymentalne, ale i tak obiecujące.

Wątek natywny potrzebuje zawsze stosu, więc odpalenie milionów natywnych wątków rozsadzi cały RAM i apka leży razem z całym systemem (w sensie OS może i nie leży, ale wpada w panikę i ubija procesy losowo). Wszelakie pseudo procesy czy wątki, które można uruchamiać w ilościach rzędu setki tysięcy naraz są wariantami zielonych wątków: https://en.wikipedia.org/wiki/Green_threads

Ogólnie kiedyś znalazłem info (teraz nie mogę go ponownie znaleźć), że Akka była inspirowana Erlangiem i autor zwyczajnie chciał przenieść Erlangowe abstrakcje do świata JVMa. Z tego co wiem (nie używałem Akki) podobno wyszło nie najgorzej.

Erlang jest przykładem modelu aktorowego, który sprawdził się w praktyce, więc Akka się na nim wzorowała. Jednak od czasów powstania Akka idzie własną drogą i przenoszenie żywcem rozwiązań z Erlanga do Akki niekoniecznie jest optymalne. W świecie Akki jest teraz moda na Reactive Streams na których oparta jest Akka-HTTP. Aktory nie są przeznaczone do samego asynchronicznego przetwarzania wiadomości, a raczej do zarządzania stanem i hierarchią nadzoru. Aktory nie mają backpressure (które jest obecne w Reactive Streams), więc mają tendencję do wypieprzania całej JVMki z powodu braku pamięci do przetwarzania wiadomości przy zbyt dużym obciążeniu. Backpressure z Akka Streams pozwala natomiast na spowolnienie obsługiwania żądań do poziomu, który jest mozliwy w danej chwili - aplikacja przetwarza żądania z pełną prędkością, ale nie zaczyna przetwarzać nowych jeśli aktualnie nie ma wolnych zasobów. Przy przeciążeniu nie ma sensu bezrefleksyjnie zaczynać przetwarzania kolejnego żądania (każde kolejne żądanie przetwarzane w tym samym czasie co inne zwiększa zapotrzebowanie na RAM), a zamiast tego lepiej skupić się na przetworzeniu do końca już rozpoczętych żądań.


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
edytowany 2x, ostatnio: Wibowit
hauleth
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:10 dni
0

@Wibowit: ale to jest od dawna stosowana praktyka, czy to poprzez supervisor z modelem simple_one_for_one (lub Elixirowy wrapper na to w postaci DynamicSupervisor od wersji 1.6) czy poprzez biblioteki jak poolboy, które używają wcześniej wymienionego mechanizmu. IIRC Cowboy również używa jakiegoś mechanizmu do back pressure (czy to poolboy czy coś innego nie pamiętam). Poza tym jakiś czas temu pojawiła się biblioteka GenStage dla Elixira, która oferuje podobne rozwiązanie. Wygląda również na to, że samo wysyłanie wiadomości jest obarczone mechanizmem backpressure (a przynajmniej było), więc to nie jest tak, że Erlangowy system "jest durny". Jednak te 9 lat różnicy między Erlangiem (1986) a Javą (1995) dają o sobie znać w takich momentach.


edytowany 1x, ostatnio: hauleth
Wibowit
  • Rejestracja:prawie 20 lat
  • Ostatnio:8 minut
0

Wygląda również na to, że samo wysyłanie wiadomości jest obarczone mechanizmem backpressure (a przynajmniej było), więc to nie jest tak, że Erlangowy system "jest durny".

Właśnie z tej podlinkowanej wiadomości wynika, że jest trochę durny. Po pierwsze działa probabilitstycznie:

sending messages to load queues is very expensive and will lead the scheduler to context switch to another process more often

'more often' nie brzmi jak jednoznaczna gwarancja. Po drugie w przypadku nowego aktora per żądanie działa odwrotnie niż powinien:

Sending messages to processes with zero messages in the queue is free in terms of reductions

Nowy aktor będzie miał pustą kolejkę wiadomości, więc priorytetem będzie zaczynanie obsługi nowych żądań zamiast kończenie już zaczętych. To nie jest dobra strategia przy przeciążeniu systemu. No chyba, że czegoś nie zrozumiałem :)

Reactive streams działają zupełnie inaczej niż aktory jeśli spojrzeć na to z której strony inicjowane jest przetwarzanie wiadomości. W mechanizmie aktorów przetwarzanie nowych wiadomości odbywa się na skutek wrzucenia ich do początkowego aktora w łańcuchu przetwarzania (proste i logiczne). W mechanizmie reactive streams przetwarzanie nowych wiadomości odbywa się na skutek zasygnalizowania przez końcówkę strumienia gotowości otrzymania nowych wiadomości. Dokładnie to jest to rozszerzone na cały strumień - poprzedni element w strumieniu jest wyłączony dopóki następny element nie zasygnalizuje mu, że jest gotowy odebrać nowe elementy. Do tego dochodzą bufory pomiędzy elementami strumienia, by zminimalizować narzut na komunikację - bufory pozwalają na ukrycie opóźnień związanych z sygnalizacją gotowości na odebranie kolejnych porcji danych.

Backpressure w Akka Streams działa bardzo podobnie do flow-control w TCP/IP: https://en.wikipedia.org/wiki/Transmission_Control_Protocol#/media/File:Tcp.svg
Można obejrzeć w akcji integrację Akka Streams z flow-control w TCP/IP tutaj:
Trzeba wziąć jeszcze pod uwagę, że Akka Streams są nieblokujące, więc to czekanie na zwolnienie bądź napełnienie się bufora TCP/ IP tak naprawdę nie blokuje żadnego wątku.
Akka Streams mają integrację nie tylko z TCP i HTTP(S), ale także z plikami ( https://doc.akka.io/docs/akka/2.5.5/scala/stream/stream-io.html#streaming-file-io ) i bazami danych ( http://slick.lightbend.com/ )


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
edytowany 1x, ostatnio: Wibowit
TurkucPodjadek
TurkucPodjadek
  • Rejestracja:około 8 lat
  • Ostatnio:około 4 lata
  • Postów:607
0
Wibowit napisał(a):

każde połączenie przychodzące to jeden niezależny proces, dzięki czemu niezłapany wyjątek nie wyłoży Ci połowy aplikacji a zwyczajnie w świecie ubije jeden proces i po sprawie (bo tak się to najzwyczajniej w Erlangu robi).

W każdym typowym JVMowym frameworku wyjątek przy obsłudze żądania nie wywala aplikacji, więc ubijanie pseudo-procesu w tej kwestii nic nie zmienia.

Słuszne spostrzeżenie, z tego co widzę (źródła wrzucili tutaj: https://github.com/bbstk/server-languages-benchmarks/) pod pojęciem "procesu" w Go oni rozumują goroutines - to nie są procesy, a wątki w go.

Goroutines to nie są wątki - goroutines to bardziej async/ await z dodatkową komunikacją.

Goroutines to takie wątki, ale w Go, ale nie są one oczywiście tożsame z wątkami w systemie operacyjnym (zdaje się o tym wspomniałem)
Tutaj jest wyjaśnione jak to działa pod spodem

Wibowit
  • Rejestracja:prawie 20 lat
  • Ostatnio:8 minut
0

Goroutines to takie wątki, ale w Go, ale nie są one oczywiście tożsame z wątkami w systemie operacyjnym

No i rozmywa się nam pojęcie wątku :] Z samego artykułu który przytoczyłeś wynika iż scheduler w Go opiera się o cooperative multitasking, a nie o preemptive multitasking. Go nie wstrzyma działającej gorutyny o ile ta gorutyna nie wejdzie w jakąś metodę, która współpracuje ze schedulerem Go. Tymczasem wątki mogą być wywłaszczone w dowolnym momencie (preemption). Formą cooperative multitasking jest np: https://en.wikipedia.org/wiki/Fiber_(computer_science)

Lepiej skupić się na konkretnych problemach i ich rozwiązaniach, a nie na nazywaniu abstrakcji, które ciężko skategoryzować.


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
edytowany 3x, ostatnio: Wibowit
hauleth
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:10 dni
0
Wibowit napisał(a):

Wygląda również na to, że samo wysyłanie wiadomości jest obarczone mechanizmem backpressure (a przynajmniej było), więc to nie jest tak, że Erlangowy system "jest durny".

Właśnie z tej podlinkowanej wiadomości wynika, że jest trochę durny. Po pierwsze działa probabilitstycznie:

sending messages to load queues is very expensive and will lead the scheduler to context switch to another process more often

'more often' nie brzmi jak jednoznaczna gwarancja. Po drugie w przypadku nowego aktora per żądanie działa odwrotnie niż powinien:

Sending messages to processes with zero messages in the queue is free in terms of reductions

Nowy aktor będzie miał pustą kolejkę wiadomości, więc priorytetem będzie zaczynanie obsługi nowych żądań zamiast kończenie już zaczętych. To nie jest dobra strategia przy przeciążeniu systemu. No chyba, że czegoś nie zrozumiałem :)

Każdy proces ma przypisane standardowo tyle samo redukcji (czasu procesora), więc źle to zrozumiałeś. To wysyłający zadania będzie miał zmniejszaną ilość redukcji, nie odbierający, więc dalej zadania będą przetwarzane tak jak było to zaplanowane. Domyślnie IIRC jest to 2000 redukcji zanim zostanie przełączony kontekst. Z racji, że w Erlangu każde zadanie z reguły to osobny proces, to w ten sposób "głodzisz" wysyłającego, a nie odbiorców.

W mechanizmie reactive streams przetwarzanie nowych wiadomości odbywa się na skutek zasygnalizowania przez końcówkę strumienia gotowości otrzymania nowych wiadomości. Dokładnie to jest to rozszerzone na cały strumień - poprzedni element w strumieniu jest wyłączony dopóki następny element nie zasygnalizuje mu, że jest gotowy odebrać nowe elementy.

Dokładnie tak działa gen_stage, gdzie to odbiorca ogranicza ile wiadomości chce otrzymać.

Trzeba wziąć jeszcze pod uwagę, że Akka Streams są nieblokujące, więc to czekanie na zwolnienie bądź napełnienie się bufora TCP/ IP tak naprawdę nie blokuje żadnego wątku.

Tak samo wysyłanie wiadomości w Erlangu. Wysłanie wiadomości nie blokuje nikogo, co najwyżej może spowodować zmianę kontekstu zaraz po wysłaniu wiadomości.

Akka Streams mają integrację nie tylko z TCP i HTTP(S), ale także z plikami ( https://doc.akka.io/docs/akka/2.5.5/scala/stream/stream-io.html#streaming-file-io ) i bazami danych ( http://slick.lightbend.com/ )

W Eliksirze masz Flow, które oferuje wsparcie dla każdego Enumerable (na ten przykład Stream), więc z automatu masz wsparcie dla plików czy DB. TCP i HTTP są z reguły obsługiwane trochę inaczej, ale z racji, że Erlang jest od początku zaprojektowany jako sRTC to ma naprawdę wiele mechanizmów, które wspierają te założenia, gdzie w Javie to programista musi bardzo często dbać o zachowanie założeń.


TurkucPodjadek
TurkucPodjadek
  • Rejestracja:około 8 lat
  • Ostatnio:około 4 lata
  • Postów:607
0
Wibowit napisał(a):

Goroutines to takie wątki, ale w Go, ale nie są one oczywiście tożsame z wątkami w systemie operacyjnym

No i rozmywa się nam pojęcie wątku :]
Z samego artykułu który przytoczyłeś wynika iż scheduler w Go opiera się o cooperative multitasking, a nie o preemptive multitasking. [/quote]

I teraz pytanie: jakie to w tym kontekście będzie miało znaczenie?

Go nie wstrzyma działającej gorutyny o ile ta gorutyna nie wejdzie w jakąś metodę, która współpracuje ze schedulerem Go.

Mogłbyś tutaj wyjaśnić, co masz dokładnie na myśli?

Tymczasem wątki mogą być wywłaszczone w dowolnym momencie (preemption). Formą cooperative multitasking jest np: https://en.wikipedia.org/wiki/Fiber_(computer_science),

Które wątki, w jakim systemie, przy jakim cpu schedulerze? Jak określamy się dokładnie to dokładnie.

Lepiej skupić się na konkretnych problemach i ich rozwiązaniach, a nie na nazywaniu abstrakcji, które ciężko skategoryzować.

Właśnie. ;-)

PS Ja wątek rozumuje prosto - zdolność do przeprowadzania różnych obliczeń dokładnie w tym samym momencie przez ten sam program, w takim sposób, że

  • jeden wątek programy jest niezależny od drugiego (np. jeden nie czeka aż drugi coś skończy)
  • ze strony OSa nie jest konieczny żaden cs do obsłużenia kolejnego wątku, jeśli logical core jest akurat "wolny"
Wibowit
  • Rejestracja:prawie 20 lat
  • Ostatnio:8 minut
0

Każdy proces ma przypisane standardowo tyle samo redukcji (czasu procesora), więc źle to zrozumiałeś. To wysyłający zadania będzie miał zmniejszaną ilość redukcji, nie odbierający, więc dalej zadania będą przetwarzane tak jak było to zaplanowane. Domyślnie IIRC jest to 2000 redukcji zanim zostanie przełączony kontekst. Z racji, że w Erlangu każde zadanie z reguły to osobny proces, to w ten sposób "głodzisz" wysyłającego, a nie odbiorców.

Jeśli to tak działa to przy tworzeniu nowego aktora dla każdego żądania tenże aktor będzie miał zapas redukcji, więc od razu zostanie odpalony i będzie wczytywał dane od klienta. Dopiero potem przytka się na przepychaniu tych danych dalej. Ale to za późno, bo już zapchał RAM danymi od klienta. Tak czy nie?

PS Ja wątek rozumuje prosto - zdolność do przeprowadzania różnych obliczeń dokładnie w tym samym momencie przez ten sam program, w takim sposób, że
jeden wątek programy jest niezależny od drugiego (np. jeden nie czeka aż drugi coś skończy)
ze strony OSa nie jest konieczny żaden cs do obsłużenia kolejnego wątku, jeśli logical core jest akurat "wolny"

Goroutines vel coroutines opierają się właśnie na nieustannym wstrzymywaniu, nieustannym cyklu suspend + resume. Jeśli jedna gorutyna chce dostać dane od innej to przy próbie odczytu z kanału jest suspend i potem scheduler Go decyduje co dalej zrobić. Dopóki kanał jest pusty to resume się oczywiście nie zrobi.

Na stronie z dokumentacją dla Go jest coś takiego - https://golang.org/doc/faq#goroutines

Why goroutines instead of threads?
Goroutines are part of making concurrency easy to use. The idea, which has been around for a while, is to multiplex independently executing functions—coroutines—onto a set of threads. When a coroutine blocks, such as by calling a blocking system call, the run-time automatically moves other coroutines on the same operating system thread to a different, runnable thread so they won't be blocked. The programmer sees none of this, which is the point. The result, which we call goroutines, can be very cheap: they have little overhead beyond the memory for the stack, which is just a few kilobytes.

Jak widać jest wyraźne rozróżnienie na wątki i gorutyny.


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
edytowany 1x, ostatnio: Wibowit
SL
  • Rejestracja:około 7 lat
  • Ostatnio:około 3 godziny
  • Postów:862
1
TurkucPodjadek napisał(a):
Wibowit napisał(a):

Go nie wstrzyma działającej gorutyny o ile ta gorutyna nie wejdzie w jakąś metodę, która współpracuje ze schedulerem Go.

Mogłbyś tutaj wyjaśnić, co masz dokładnie na myśli?

Taki prosty przykład https://stackoverflow.com/questions/25073815/golang-goroutine-infinite-loop .

hauleth
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:10 dni
0
Wibowit napisał(a):

Każdy proces ma przypisane standardowo tyle samo redukcji (czasu procesora), więc źle to zrozumiałeś. To wysyłający zadania będzie miał zmniejszaną ilość redukcji, nie odbierający, więc dalej zadania będą przetwarzane tak jak było to zaplanowane. Domyślnie IIRC jest to 2000 redukcji zanim zostanie przełączony kontekst. Z racji, że w Erlangu każde zadanie z reguły to osobny proces, to w ten sposób "głodzisz" wysyłającego, a nie odbiorców.

Jeśli to tak działa to przy tworzeniu nowego aktora dla każdego żądania tenże aktor będzie miał zapas redukcji, więc od razu zostanie odpalony i będzie wczytywał dane od klienta. Dopiero potem przytka się na przepychaniu tych danych dalej. Ale to za późno, bo już zapchał RAM danymi od klienta. Tak czy nie?

Nie do końca, bo jak odpalasz spawn/1 to taki proces dopiero ląduje w kolejce schedulera, nie oznacza, że jest od razu odpalany, więc jeśli rodzic po odpaleniu procesu ma jeszcze jakieś redukcje to jeszcze będzie się wykonywał. Kolejną rzeczą, jest że w Erlangu również jest event loop, który działa w osobnym wątku i cała komunikacja między światem zewnętrznym a procesami Erlanga również odbywa się na zasadzie wymiany wiadomości, więc proces będzie czekał aż otrzyma wiadomość z event loopa z danymi. Więc "pod spodem" działa to podobnie do goroutines, ale daje Ci wyższy poziom abstrakcji i ukrywa implementacyjne szczegóły. Kolejną rzeczą jest fakt, że procesy z reguły żyją krótko (generational hypothesis), więc GC może często zwyczajnie wyrzucić całość pamięci jaka była przydzielona danemu procesowi bez przejmowania się (https://www.erlang-solutions.com/blog/erlang-garbage-collector.html). Więc to nie Agent bezpośrednio czyta dane, a VMka i potem przekazuje te dane do agenta jak coś się pojawi.


Wibowit
  • Rejestracja:prawie 20 lat
  • Ostatnio:8 minut
0

Hmm, dziwnie to opisałeś. Podam przykład:

  • robię sobie pseudo-chmurę plikową
  • sto tysięcy ludków chce mi wysłać pliki naraz
  • moja chmura przycina się na zapisie danych
  • Erlang dla każdego żądania tworzy nowego aktora i to mu idzie sprawnie
  • aktor do zapisu danych jest przyblokowany
  • nowe aktory obsługujące żądania jednak zaczynają od wczytywania plików od klientów, co zapycha RAM
  • jak już aktor od żądania wczyta trochę danych do RAMu to chce to zapisać z użyciem aktora do zapisu ale w tym momencie się przycina (bo aktor do zapisu jest przyblokowany)
  • dużo czasu procesora jest wolne więc Erlang tworzy nowe aktory do obsługi żądań, które zapychają jeszcze więcej RAMu i zaczyna się panika
  • co robić?

Zaznaczam, że nie wiem jak Erlangowe mechanizmy działają, więc być może przykład nie ma pokrycia w rzeczywistości. Jednak z tych opisów co tutaj podałeś wynika, że taki scenariusz jest możliwy.


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
edytowany 1x, ostatnio: Wibowit
hauleth
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:10 dni
0

@Wibowit: ogólnie całe IO przechodzi przez epoll (w nowych wersjach), więc cały system działa w drugą stronę, czyli jak chcesz pisać do pliku to wysyłasz wiadomość do procesu i otrzymujesz karę jeśli jest zajęty. Więc powoli to wszystko idzie wstecz. Więc system da radę (bo epoll będzie stopował procesy).

Alternatywnie jak masz naprawdę ograniczone zasoby, np. ograniczoną ilość połączeń z DB to można użyć poolboya (tego np. używa Cowboy do ograniczenia ilości połączeń przychodzących i Ecto do posiadania puli ciągłych połączeń z DB) lub jeśli jest to przetwarzanie danych to można użyć Elixirowej biblioteki GenStage, która trochę przypomina reaktywne programowanie, gdzie to konsument określa ile jest w stanie na raz zrobić (oraz wrapper na to Flow, który oferuje przyjaźniejszy interfejs do części zadań).


Wibowit
  • Rejestracja:prawie 20 lat
  • Ostatnio:8 minut
0

Hmm, no i okazuje się, że Erlang automagicznie nie zabezpiecza nas przed wysadzeniem VMki przy przeciążeniu serwera tylko musimy sobie podokładać jakieś biblioteki i używać ich zgodnie z przeznaczeniem. Tak to jest na każdej innej platformie, różnica jest tylko w składni i co za tym idzie - wygodzie.


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
hauleth
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:10 dni
0

Oczywiście, że nie zabezpiecza, ale czyni napisanie kodu, który mógłby zabić VMkę zdecydowanie trudniejszym. Tak to będzie gdy masz platformę od początku zaprojektowaną na to by była soft real-time. Ale zabezpieczyć w 100% się nigdy nie da.


0

Wybieram najnowszy Swift z 2014 roku.

KR
Przecież Swift to kiepski ripoff Scali. Może z 2014, ale bazuje na języku z 2003 :P
LS
Objective-C to ripoff Smalltalka z kolei. Niestety C++ przyjęło się bardziej przez co ten ripoff został uznany za kiepski :(
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)