Jak działa I / O w Akka?

Jak działa model aktora (w Akce), gdy trzeba wykonać I/o (tj. operacja bazy danych)?

Rozumiem, że operacja blokująca spowoduje wyrzucenie wyjątku (i zasadniczo zrujnuje wszystkie współbieżności ze względu na wyrównaną naturę Netty, której używa Akka). Dlatego musiałbym użyć Future lub czegoś podobnego-jednak nie rozumiem modelu współbieżności.

  1. czy 1 aktor może przetwarzać wiele wiadomości jednocześnie?
  2. Jeśli aktor robi blokowanie wywołania w future (tj. future.get()) czy blokuje to tylko wykonanie aktualnego aktora; czy też uniemożliwi wykonanie wszystkich aktorów do czasu zakończenia połączenia blokującego?
  3. jeśli blokuje wszystkie wykonanie, jak działa używanie przyszłej współbieżności assist (tj. czy wywołanie blokowania połączeń w przyszłości nie byłoby jeszcze równoznaczne z utworzeniem aktora i wykonaniem połączenia blokującego)?
  4. jaki jest najlepszy sposób radzenia sobie z procesem wielostopniowym (tj. odczyt z bazy danych; wywołanie usługi blokującej; odczyt z bazy danych; zapis do bazy danych) gdzie każdy krok jest zależny od ostatniego?

Podstawowy kontekst jest następujący:

  • używam serwera Websocket, który utrzyma tysiące sesji.
  • każda sesja ma jakiś stan (tj. szczegóły uwierzytelniania itp.);
  • Klient Javascript wyśle wiadomość JSON-RPC do serwera, który przekaże ją do odpowiedniego aktora sesji, który ją wykona i zwróci wynik.
  • wykonanie RPC połączenie będzie obejmować niektóre wejścia / wyjścia i blokowanie połączeń.
  • będzie duża liczba jednoczesnych żądań (każdy użytkownik będzie składał znaczną ilość żądań przez połączenie WebSocket i będzie dużo użytkowników).
Czy jest lepszy sposób, aby to osiągnąć?
Author: Ahmet Alp Balkan - Google, 2011-06-30

3 answers

Operacje blokujące nie rzucają WYJĄTKÓW w Akce. Możesz robić blokowanie połączeń od aktora (które prawdopodobnie chcesz zminimalizować, ale to już inna historia).

  1. nie, 1 instancja aktora nie może.
  2. Nie blokuje innych aktorów. Możesz na to wpłynąć, korzystając z konkretnego dyspozytora. Futures używa domyślnego dispatchera (Zwykle globalnego wywołanego zdarzeniami), więc działa na wątku w Puli. Możesz wybrać, którego dyspozytora chcesz użyć dla swoich aktorów (za aktor, lub dla wszystkich). Myślę, że jeśli naprawdę chcesz stworzyć problem, możesz być w stanie przekazać dokładnie ten sam (oparty na wątkach) dyspozytor do kontraktów futures i aktorów, ale to wymaga pewnych intencji z twojej strony. Myślę, że jeśli masz ogromną liczbę kontraktów terminowych blokujących w nieskończoność, a executorservice został skonfigurowany do określonej liczby wątków, możesz wysadzić executorservice. Dużo "jeśli". f. pobierz bloki tylko wtedy, gdy przyszłość nie została jeszcze zakończona. Zablokuje " bieżący thread ' of the Actor from which you call it (jeśli nazywasz go od aktora, co nie jest konieczne przy okazji) Nie musisz blokować. możesz użyć oddzwaniania zamiast f.get. Możesz nawet komponować Kontrakty terminowe bez blokowania. więcej szczegółów znajdziesz w artykule Viktora pt. "obiecująca przyszłość Akki": http://skillsmatter.com/podcast/scala/talk-by-viktor-klang
  3. użyłbym komunikacji asynchronicznej pomiędzy krokami (jeśli kroki są znaczącymi procesami na własne), więc użyj aktora dla każdego kroku, gdzie każdy aktor wysyła wiadomość oneway do następnego, ewentualnie również wiadomości oneway do innego aktora, który nie zablokuje, który może nadzorować proces. W ten sposób można tworzyć łańcuchy aktorów, z których można zrobić wiele, przed nim można umieścić aktora równoważenia obciążenia, tak, że jeśli jeden aktor blokuje w jednym łańcuchu inny tego samego typu może nie w drugim łańcuchu. To by też zadziałało na twoje pytanie "kontekstowe", przekazanie obciążenia pracą do lokalni aktorzy, łańcuch ich za aktorem równoważącym obciążenia.

Jeśli chodzi o netty (a zakładam, że masz na myśli aktorów zdalnych, bo to jedyna rzecz, do której netty jest używany w Akce), przekaż swoją pracę jak najszybciej do lokalnego aktora lub przyszłości (z callback), jeśli martwisz się o czas lub uniemożliwienie netty ' emu wykonania swojej pracy w jakiś sposób.

 27
Author: Raymond Roestenburg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-30 06:41:36

Operacje blokujące zazwyczaj nie wyrzucają wyjątków, ale oczekiwanie na przyszłość (na przykład przy użyciu metod !! lub !!! send) może wyrzucić wyjątek time out. Dlatego powinieneś trzymać się fire-and-forget jak najwięcej, używać znaczącej wartości czasu i preferować oddzwanianie, gdy to możliwe.

  1. Aktor akka nie może jawnie przetworzyć kilku wiadomości pod rząd, ale możesz grać z wartością throughput poprzez plik konfiguracyjny. Aktor będzie następnie przetwarzał kilka wiadomości (tzn. jej metoda odbioru zostanie wywołana kilka razy sekwencyjnie), jeśli kolejka wiadomości nie jest pusta: http://akka.io/docs/akka/1.1.3/scala/dispatchers.html#id5

  2. Blokowanie operacji wewnątrz aktora nie spowoduje "zablokowania" wszystkich aktorów, ale jeśli współdzielisz wątki między aktorami( zalecane użycie), jeden z wątków dyspozytora zostanie zablokowany do czasu wznowienia operacji. Więc spróbuj komponować przyszłość jak najwięcej i uważaj na przerwę wartość).

3 i 4. Zgadzam się z Raymond answers.

 10
Author: paradigmatic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-21 14:31:19

To, co powiedział Raymond i paradigmatic, ale także, jeśli chcesz uniknąć zagłodzenia puli wątków, powinieneś zawinąć wszelkie operacje blokujące w scala.concurrent.blocking.

Oczywiście najlepiej unikać operacji blokowania, ale czasami trzeba użyć biblioteki, która blokuje. Jeśli zawiniesz ten kod w blocking, poinformuje to kontekst wykonania, że możesz zablokować ten wątek, aby w razie potrzeby mógł przydzielić inny.

Problem jest gorszy niż opisuje paradygmat, ponieważ jeśli masz kilka blokowanie operacji możesz zablokować wszystkie wątki w puli wątków i nie mieć wolnych wątków. Możesz skończyć z impasem, jeśli wszystkie twoje wątki są zablokowane na czymś, co nie stanie się, dopóki inny aktor / przyszłość nie zostanie zaplanowana.

Oto przykład:

import scala.concurrent.blocking
...

Future {
  val image = blocking { load_image_from_potentially_slow_media() }
  val enhanced = image.enhance()
  blocking {
    if (oracle.queryBetter(image, enhanced)) {
      write_new_image(enhanced)
    }
  }
  enhanced
}

Dokumentacja jest tutaj .

 1
Author: aij,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-27 19:55:00