Synchronizacja wielu obiektów

Poniższy program ilustruje użycie sygnałów i obietnic do synchronizacji pracy wielu obiektów w POOL. W przykładzie obiekt klasy supervisor obsługuje asynchronicznie napływające zadania, rozdzielając je pomiędzy dostępne obiekty klasy worker. Jeśli wszystkie obiekty worker są zajęte, zadania są zapisywane w buforze i wykonywane w momencie pojawienia się wolnych obiektów.
Obiekt sender pozwala sterować długością zadań (agumenty funkcji prep) i częstotliwością ich wysyłania (argumenty instrukcji timer) - używając tych parametrów możesz dostosować ilość i długość zadań do wydajności komputera. Zbyt duże obciążenie będzie skutkowało ciągłym zwiększaniem liczby zadań odłożonych do bufora.

Przykład:

to worker :n ;klasa obiektów wykonujących obliczenia
  to do_work :inp :len
    repeat :len ["inp += (runif -0.0001 0.0001)]
    signal "done ;wyślij sygnał zakończenia zadania
    op :inp      ;i zwróć obliczoną wartość
  end
  "idx := :n
  signal "ready  ;sygnał na zakończenie konstruktora
end

to supervisor :n ;klasa obiektu rozdzielającego zadania
  to onsignaldone :turtle
    :njobs,(:idx @ :turtle) += 1 ;zliczaj zadania wykonane przez tego workera
    queue :free :turtle          ;i dodaj go do listy dostępnych zasobów
    if not empty? :buffer [signal "dobuffer;spróbuj wykonać odłożone zadania
  end

  to onsignalwork :turtle :data  ;obsługa nadchodzących danych
    if empty? :free [ ;wszystkie zasoby zajęte, odłóż dane na później
      queue :buffer :data
      (print "|odłóż zadanie| count :buffer)
      op false
    ]
    ;wyślij zadanie do workera, zapisz wynik jako "obietnicę"
    :a,(:data,3) := (do_work :data,1 :data,2) @ dequeue :free
    op true
  end

  let "buffer []
  to onsignaldobuffer
    while not empty? :buffer [
      if not onsignalwork this dequeue :buffer [stop]
      if empty? :buffer [print "|odłożone zadania zakończone|]
    ]
  end

  let "free []
  repeat :n [queue :free (anewobject $worker repcount)]
  (waitsignal "ready :free;zaczekaj na zakończenie konstruktorów
  "njobs := (newarray :n 0)

  "t := timer [(print "|wykonane zadania:| :njobs)] 3000
end

to sender ;klasa obiektu wysyłającego dane
  let "j 0
  to prep :len ;wyślij następną wartość z :a
    let "i 1 + :j % count :a
    if number? :a,:i [ ;jakakolwiek operacja na wartości zaczeka na ewentualną poprzednią "obietnicę"
      (signal "work (array :a,:i :len :i))
    ]
    "j += 1
  end
  "r1 := timer [prep 300000] 50 ;często wysyłaj krótkie zadania
  "r2 := timer [                ;a czasem wyślij długie zadanie
    if random 3 < 1 [print "|wyślij długie zadanie| prep 5000000]
  ] 500
end

(shared "s "a)
"a := (newarray 1000 0)
"sup := (newobject $supervisor :sys_inf,"cpu_count)
"send := newobject $sender

"p := newp "pool [
  "t := timer ["data := (histogram :a 50 (-0.2) 0.2) refresh] 1000
]
:pool_cfg,"min_x := -0.3
:pool_cfg,"max_x := 0.3
:pool_cfg,"min_y := 0
:pool_cfg,"max_y := 300
ht

Rezultat wykonania:

wykonane zadania: {0 0 0 0}
wyślij długie zadanie
wyślij długie zadanie
wykonane zadania: {17 7 17 14}
odłóż zadanie 1
odłożone zadania zakończone
odłóż zadanie 1
odłóż zadanie 2
odłożone zadania zakończone
wykonane zadania: {35 13 34 23}
wyślij długie zadanie
wykonane zadania: {50 28 49 38}
...

Zobacz także:

Żółw - wykres - obiekt

Spis treści