$BJB9T%7%9%F%`(B $B%7%9%F%`>pJs7O(B/$B>pJs9)3X0h(B, $B%7%9%F%`>pJs9)3X8&5f72(B/$B>pJsM}9)3X0L%W%m%0%i%`(B $B%7%9%F%`>pJs9)3X8&5f2J(B/$B%3%s%T%e!<%?%5%$%(%s%9@l96(B $B?7>k(B $BLw(B <yas@cs.tsukuba.ac.jp>
$B$3$N%Z!<%8$O!"
http://www.cs.tsukuba.ac.jp/~yas/cs/csys-2023/2023-06-16
$B$"$k$$$O!"
http://www.cs.tsukuba.ac.jp/~yas/cs/
http://www.cs.tsukuba.ac.jp/~yas/
$B;29MJ88%(B References
$B8@8l$H$7$F$O!"2?
$B8=:_$G$O!"%"%/%?$r!V(B($BJB9T(B)$B%*%V%8%'%/%H!W$HFI$_BX$($k$HJ,$+$j$d$9$$!#(B
$B?^(B? $B%"%/%?$N4pK\35G0(B/Basic concepts of the Actor model
$B%"%/%?$O!"%a%C%;!<%8$r
$B%"%/%?$,%a%C%;!<%8$r
$BMWAG(B
$B%"%/%?$O!"%a%C%;!<%8$rAw$B"!7QB3(B/Continuations
$B7QB3(B(continuation$B!"7QB3E@$H$b$$$&(B)$B$rMQ$$$k!#(B
$B5f6K$N(B goto $BJ8!#(BC $B8@8l$N4X?t$G(B
goto f(1, 2, 3);
$B$N$h$&$J$b$N!#(B
$BDL>o$N3,>h(B(in Scheme)
(define (fact n) (if (= n 0) 1 (* n (fact (- n 1)))))$B7QB3$r
(define (fact-c n c) (if (= n 0) (c 1) (let ((c2 (lambda (x) (c (* n x))))) (fact-c (- n 1) c2))))
$B
6
> (fact 4)
24
> (fact-c 3 print)
6> (fact-c 4 print)
24>
factorial$B-q&K(Bm. match m <n c> if n = 1 then (send c <1>) else if n > 1 then (send factorial <(n-1) ($B&K(Bk.(send c <n * k>))>)3$B$N3,>h$r7W;;$7$F!"7QB3(Bprint_answer$B$KAw$j$?$$;~$K$O!"(B $B (send factorial <3 print_answer>)
(define (Factorial( )) (Is-Communication (a doit (with customer =m) (with number =n)) do (become Factorial) (if (NOT (= n 0)) (then (send m 1)) (else (let (x = (new FactCust (with customer m) (with number n))) (send Factorial (a do (with customer x) (with number (- n 1))))))))) (define (FactCust (with customer =m) (with number =n)) (Is-Communicaton (a number k) do (send m (* n k))))
$B?6$kIq$$5-=R(B (define ($BL>A0(B (with id $B%Q%?%s(B)) $BDL?.%O%s%I%i$NJB$S(B) $BDL?.%O%s%I%i(B (Is-Communication $B%Q%?%s(B do $B%3%^%s%I(B) let$B%3%^%s%I(B (let ($BJQ?tL>(B = $B<0(B) do $B%3%^%s%I(B) $B>r7o%3%^%s%I(B (if $B<0(B (then do $B%3%^%s%I$NJB$S(B) (else do $B%3%^%s%I$NJB$S(B)) $B%a%C%;!<%8Aw?.%3%^%s%I(B (send $B%a!<%k%\%C%/%9(B $BCM(B) becom$B%3%^%s%I(B (become $B<0(B) $B?7$7$$%"%/%?$N@8@.(B (new $B<0(B)
(define (Account (with Balance =b)) (Is-Request (a Balance) do (become (Account (with Balance b))) (reply b)) (Is-Request (a Deposit (with Amount =a)) do (become (Account (with Balance (+ b a)))) (reply (a Deposit-Receipt (with Amount a)))) (Is-Request (a Withdrawal (with Amount =a)) do (if (> a b) (then do (become (Account (with Balnce b))) (complain (an Overdraft))) (else do (become (Account (with Balnce(- b a)))) (reply (a Withdrawal-Receipt (with Amount a)))))))
import akka.actor.typed.scaladsl.Behaviors import akka.actor.typed.{ActorRef, Behavior} object Counter { sealed trait Command case object Increment extends Command final case class GetValue(replyTo: ActorRef[Value]) extends Command final case class Value(n: Int) def apply(): Behavior[Command] = counter(0) private def counter(n: Int): Behavior[Command] = Behaviors.receive { (context, message) => //$B"(#1(B message match { case Increment => val newValue = n + 1 context.log.debug("Incremented counter to [{}]", newValue) counter(newValue) //$B"((B2 case GetValue(replyTo) => replyTo ! Value(n) Behaviors.same } } }
// This function launches a new counter actor fun CoroutineScope.counterActor() = actor<CounterMsg> { var counter = 0 // actor state for (msg in channel) { // iterate over incoming messages when (msg) { is IncCounter -> counter++ is GetCounter -> msg.response.complete(counter) } } }
fun main() = runBlocking { val counter = counterActor() // create the actor withContext(Dispatchers.Default) { massiveRun { counter.send(IncCounter) } } // send a message to get a counter value from an actor val response = CompletableDeferred<Int>() counter.send(GetCounter(response)) println("Counter = ${response.await()}") counter.close() // shutdown the actor }
a = actor {...}
$B$G!"%"%/%?@8@.!#L58B%k!<%W4^$`!#(B
defmodule Counter do def start(initial_count) do spawn fn -> listen(initial_count) end end def listen(count) do receive do :inc -> listen(count + 1) {sender, :val} -> send sender, count listen(count) end end end iex> counter_pid = Counter.start(10) #PID<...> iex> send counter_pid, :inc :inc iex> send counter_pid, :inc :inc iex> send counter_pid, :inc :inc iex> send counter_pid, {self, :val} {#PID<...>, :val} iex> receive do ...(13)> value -> value ...(13)> end 13
$B%+%&%s%?$NNc!#(B
1: #!/opt/local/bin/ruby3.0 2: 3: Warning[:experimental] = false 4: 5: class CounterActor 6: def initialize(val) 7: @r = Ractor.new(val) {|val| 8: loop { 9: msg = Ractor.receive() 10: case msg 11: in [:inc] 12: val += 1 13: in [:getvalue, c] 14: c.send(val) 15: end 16: } 17: } 18: end 19: def send( msg ) 20: @r.send( msg ) 21: end 22: end 23: 24: c = CounterActor.new(10) 25: 26: c.send([:inc]) 27: c.send([:inc]) 28: c.send([:getvalue, Ractor.current()]) 29: v = Ractor.receive() 30: printf("Counter value == %d\n",v)$B
$B#13,=R8lO@M}$NO@M}<0$O!"
P 1 $B"K(B P 2 $B"K(B ... $B"K(B P n $B"+(B Q 1 $B"J(B Q 2 $B"J(B ... $B"J(B Q n.
$B!V"+!W$N:8$,$?$+$@$+(B1$B8D$N$b$N$,%[!<%s@a(B(Horn clause)$B!#(B(OR$B$,J#?t=q$-$?$/(B
$B$J$C$?$i!"J#?t9T$K$o$?$C$F=q$/(B)$B!#%[!<%s@a$K$O(B3$B
fatherof(isaac,abraham). -- isaac $B$NIc$O(B abraham $B$G$"$k(B fatherof(ishmail,abraham). fatherof(shuah,abraham). fatherof(jacob,isaac). fatherof(esau,isaac). fatherof(reuben,jacob). fatherof(dinah,jacob). fatherof(dan,jacob). fatherof(asher,jacob). fatherof(joseph,jacob). motherof(isaac,sarah). -- isaac $B$NJl$O(B sarah $B$G$"$k!#(B motherof(ishmail,hagar). motherof(shuah,ketura). motherof(jacob,rebeccah). motherof(easu,rebeccah). motherof(reuben,leah). motherof(dinah,leah). motherof(dan,bilhah). motherof(asher,zilpah). motherof(joseph,rachel).
"_"
$B$O!"L5L>JQ?t!#CM$O;D$i$J$$!#(B
"motherof(isaac,_)?"
$B$N"fatherof(_,_)"
$B$N"fatherof(joseph,X)"
$B$N"X"
$B$O!"(B"jacob"
$B$KB+G{(B(bind)$B$5$l$F$$$k!#(B
"motherof(C,leah)?"
$B$N"C=dinah"
$B$H$$$&B+G{$,5/$-$k$3$H$,$"$k!#(B
parentof(C,P) :- motherof(C, P). -- P $B$,(B C $B$NJl$J$i!"(B P $B$O(B C $B$N?F$G$"$k!#(B parentof(C,P) :- fatherof(C, P). -- P $B$,(B C $B$NIc$J$i!"(B P $B$O(B C $B$N?F$G$"$k!#(B grandparentof(C,GP) :- parentof(C,P), parentof(P,GP). -- C $B$N?F$,(B P $B$G!"$+$D!"(BP $B$N?F$,(B GP $B$J$i!"(BGP $B$O(B C $B$NADIcJl$G$"$k!#(B ancestor(C,A) :- parentof(C,A). ancestor(C,A) :- parentof(C,P), ancestor(P,A). -- C $B$N?F$,(B P $B$G!"$+$D!"(BP $B$NAD@h$,(B A $B$J$i$P!"(BA $B$O(B C $B$NAD@h$G$"$k!#(B
append([],Y,Y). append([A|B],Y,[A|B1]) :- append(B,Y,B1).
$B?^(B? Prolog $B$N(B append
quicksort(List,Sorted) :- qsort(List, Sorted, []). qsort([],H,H). qsort([A|B],H,T) :- partition(B,A,S,L), qsort(S,H,[A|T1]), qsort(L,T1,T). partition([],X,[],[]). partition([A|B],X,[A|S],L) :- A<X, partition(B,X,S,L). partition([A|B],X,S,[A|L]) :- A>=X, partition(B,X,S,L).
$B?^(B? Prolog $B$K$h$k%/%$%C%/%=!<%H(B
quicksort $B$K$"$kJBNs@-!#(BParallelism in quicksort.H :- G 1, G 2,...,G n | B 1, B 2, ..., B m.
$B!V(B|$B!W$O!"%3%_%C%H1i;;;R!#(B G 1, G 2,...,G n $B$O%,!<%IIt!#(B B 1, B 2, ..., B m $B$O!"%\%G%#It!#(Bappend([A|X1],Y,Z) :- true | Z = [A|Z1], append(X1,Y,Z1). append([],Y,Z) :- true | Z=Y.Prolog $B$J$i$3$&$J$k(B
append([A|X1],Y,[A|Z1]) :- append(X1,Y,Z1). append([],Y,Y).
quicksort(Xs,Ys) :- true | qsort(Xs, Ys-[]). qsort([X|Xs],Ys0-Ys3) :- true | partition(Xs,X,S,L), qsort(S,Ys0-Ys1), Ys1=[X|Ys2], qsort(L,Ys2-Ys3). qsort([],Ys0-Ys1) :- true | Ys0 = Ys1. partition([X|Xs],A,S,L0) :- A<X | L0=[X|L1], partition(Xs,A,S,L1). partition([X|Xs],A,S0,L) :- A>=X | S0=[X|S1], partition(Xs,A,S1,L). partition([],A,S,L) := true | S=[], L=[].
1999$BG/$K!"%5%s!&%^%$%/%m%7%9%F%`%:
Jini $B$NL\I8$O!"%M%C%H%o!<%/$G(B Plug & Play $B$r
$BL\I8(B
JavaSpaces $B$O!"FbItE*$K(B Jini $B$N%k%C%/%"%C%W!&%5!<%S%9$N
Jini $B$N%/%i%9%i%$%V%i%j$O!"(B
JavaSpaces $B$N2s(B
$B$G>R2p$7$?(B
Apache River
$B$,MxMQ$G$-$k!#(B
Microsoft $B$N!"(BJini $B$KBP93$7$?5;=Q!#(B
$B"!(BUPnP (Universal Plug and Play)
$B"!%k%C%/%"%C%W!&%5!<%S%9(B/Loockup service in Jini
Jini$BCf?4E*$J5;=Q$,!"%k%C%/%"%C%W!&%5!<%S%9!#(B
$B%5!<%S%9$NEPO?$H8!:w(B
$B%k%C%/%"%C%W!&%5!<%S%9<+?H$b!":G=i$+$iCN$i$l$F$$$kI,MW$O$J$$!#(B $B%M%C%H%o!<%/>e$G<+F0E*$KC5$5$l$k!#(B Discovery $B$H(B Join$B!#(B
Java $B$N%*%V%8%'%/%H$,(B Lease$B!#(B
$B%j!<%94|4V$O!"1dD9$9$k$3$H$,$G$-$k!#(B $B1dD9$5$l$J$+$C$?(B lease $B$O!"%k%C%/%"%C%W!&%5!<%S%9$+$i:o=|$5$l$k!#(B $BEPO?$5$l$F$$$k%5!<%S%9$rL@<(E*$K:o=|$9$k;EAH$_$O!"B8:_$7$J$$!#(B
$B%5!<%S%9$,:o=|$5$l$?;~$K$O!"J,;67?%$%Y%s%HG[Aw%5!<%S%9$K$h$j4X78$7$F$$(B $B$k=j$KCN$i$5$l$k!#(B
$B%H%i%s%6%/%7%g%s$N%$%s%?%U%'!<%9$ODj$a$i$l$F$$$k$,!"6qBNE*$J
$B"!(BJini$B$r;H$&$N$KI,MW$H$5$l$F$$$k$b$N(B/Requirements to run Jini
IP$B%"%I%l%9$N3d$jEv$F$O!"(BJini$B$N0lIt$G$O$J$$!#(B
$B%5!<%S%9$NDs6!
ServiceIDLister $B%$%s%?%U%'!<%9$r(B implements $B$9$k!#(B
package com.sun.jini.lookup;
public interface ServiceIDListener extends java.util.EventListener {
void serviceIDNotify(net.jini.core.lookup.ServiceID serviceID);
}
$B%k%C%/%"%C%W!&%5!<%S%9$+$i%3!<%k%P%C%/$5$l$k!#(B
Discovery $B$N
$B?^(B1 $B%^%k%A%-%c%9%H$K$h$k(B Discovery/Discovery by multicast
$B?^(B2 Join
$B%0%k!<%W$O!"L>A0(B($BJ8;zNs(B)$B$G6hJL$5$l$k!#(B
Jini $B%Q%C%1!<%8$O!"(BJoinManager $B$H$$$&;2>H%/%i%9$r4^$`!#(B
public JoinManager(Object obj, Entry[] attrSets, ServiceIDListener callback, LeaseRenewalManager leaseMgr) throws IOException public JoinManager(Object obj, Entry[] attrSets, String[] groups, LookupLocator[] locators, ServiceIDListener callback, LeaseRenewalManager leaseMgr ) throws IOException
import java.rmi.*; public interface RemoteBall extends Remote { public void hit() throws java.rmi.RemoteException; }
import java.rmi.*; import java.rmi.server.*; import net.jini.core.lookup.*; import com.sun.jini.lookup.*; public class Ball extends UnicastRemoteObject implements RemoteBall, ServiceIDListener { public Ball() throws RemoteException { super(); } public void serviceIDNotify(ServiceID id) { System.out.println("ServiceId is "+id); } public void hit() { System.out.println("Ball has been hit"); } }
import java.rmi.*; import net.jini.core.entry.*; import net.jini.lookup.entry.*; import com.sun.jini.lookup.*; import com.sun.jini.lease.*; public class BallStarter { public static void main(String[] args) { try { System.setSecurityManager(new RMISecurityManager()); RemoteBall ball = (RemoteBall) new Ball(); LeaseRenewalManager renewal = new LeaseRenewalManager(); Entry[] attributes = new Entry [] { new Name("Jini enabled ball")}; JoinManager join = new JoinManager( ball, attributes, (Ball) ball, renewal ); System.out.println("Ball started and registered at Lookup-Server"); } catch (Exception e) { e.printStackTrace(); } } }
$B?^(B3 Lookup
$B%5!<%S%9$O!"public ServiceTemplate(ServiceID serviceID, Class[] serviceTypes, Entry[] attrSetTemplates)$B%5!<%S%9(B($B%*%V%8%'%/%H(B)$B$NC5$7J}(B
import java.rmi.*; import net.jini.core.discovery.*; import net.jini.core.lookup.*; public class Bat { public Ball ball; public void play(RemoteBall ball) { try { ball.hit(); System.out.println("I hit the ball"); } catch (RemoteException e) { System.out.println(e); } } public static void main (String[] args) { Bat bat = new Bat(); try { System.setSecurityManager(new RMISecurityManager()); LookupLocator locator = new LookupLocator("jini://localhost"); ServiceRegistrar registrar = locator.getRegistrar(); Class[] classes = new Class[] { RemoteBall.class }; ServiceTemplate template = new ServiceTemplate( null, classes, null); RemoteBall remoteBall = (RemoteBall) registrar.lookup(template); bat.play(remoteBall); } catch (Exception e) { e.printStackTrace(); } } }
$B?.Mj@-$,Dc$$%M%C%H%o!<%/$H!"$I$&@o$&J}K!$N#1$D!#(B
lease $B$K$O!"4|8B$,$"$k!#(B
$B4|8B$ND9$5$O!"8r>D2DG=!#(B $B4|8B$,C;$$(B(1$BJ,0J2
$B%j!<%9$NMxE@(B
Jini $B$N%5!<%S%9$rDs6!$7$F$$$k%*%V%8%'%/%H$O!"(BLease $B%$%s%?%U%'!<%9$r
public interface Lease { long FOREVER = Long.MAX_VALUE; ... long getExpiration(); void renew(long duration) throws LeaseDeniedException, UnknownLeaseException, RemoteException; void cancel() throws UnknownLeaseException, RemoteException; ... }getExpiration() $B$G!"%j!<%9$N;D$j;~4V$,$o$+$k!#%_%jICC10L!#(B
renew() $B$G1dD9$9$k!#(B $B1dD9$G$-$J$$;~$K$O!"(BLeaseDeniedException $B$,JV$5$l$k!#(B
$B$b$&;H$o$J$/$J$C$?;~$K$O!"(Bcancel() $B$G$-$k!#(B $B4|8B@Z$l$HF1$8$3$H$K$J$k!#(B
$B%j!<%9$N4IM}$K$O!"(BLeaseRenewalManager $B$r;H$&!#(B
In Scala, Kotlin, Elixir, and Ruby Ractor, we can write a program based on a kind of the actor model. Choose one language from these languages, and provide how to describe the following operations in the language.
Jini $B$K$*$$$F!"(Bplug and play $B$r
Yasushi Shinjo / <yas@cs.tsukuba.ac.jp>