Dataflow behaviour in a concurrent setting. Consider the function {Filter In F}, which returns the elements of In for which the boolean function F returns true. Here is a possible definition of Filter:
fun {Filter In F}
case In
of X|In2 then
if {F X} then X|{Filter In2 F}
else {Filter In2 F} end
else
nil
end
endExecuting the following:
{Show {Filter [5 1 2 4 0] fun {$ X} X>2 end}}displays
[5 4](We use the procedure Show, which displays the instantaneous value of its argument in Mozart’s emulator window. Unlike Browse, this output is not updated if the argument is subsequently bound.) So Filter works as expected in the case of a sequential execution when all the input values are available. Let us now explore the dataflow behaviour of Filter.
a) What happens when we execute the following?:
declare A
{Show {Filter [5 1 A 4 0] fun {$ X} X>2 end}}A that is not yet bound to a value. Remember that the case and if statements will suspend the thread in which they execute, until they can decide which alternative path to take.
b) What happens when we execute the following?:
declare Out A
thread Out={Filter [5 1 A 4 0] fun {$ X} X>2 end} end
{Show Out}Show displays its argument as it exists at the instant of the call. Several possible results can be displayed. Which and why? Is the Filter function deterministic? Why or why not?
c) What happens when we execute the following?:
declare Out A
thread Out={Filter [5 1 A 4 0] fun {$ X} X>2 end} end
{Delay 1000}
{Show Out}{Delay N} suspends its thread for at least N ms. During this time, other ready threads can be executed.
d) What happens when we execute the following?:
declare Out A
thread Out={Filter [5 1 A 4 0] fun {$ X} X>2 end} end
thread A=6 end
{Delay 1000}
{Show Out}a) Nothing is displayed because Filter is suspended waiting on A to become bound.
b) What gets displayed on my box is Out<optimized>. But when I use the Browser I see 5|_. Another possible value would _ if Show is executed before Filter. But even though there can be different values shown doesn’t mean that Filter itself is not deterministic. What’s not deterministic is the way threads are executed and Show is probably not part of the declarative model.
c) This displays 5|_<optimized>. So it seems that the calls to Show in b) that I got were all before the call to Filter.
d) This of course displays [5 6 4]. Filter can finish because A gets bound, and we are waiting long enough before calling Show.
Dataflow behaviour in a concurrent setting. Consider the function {Filter In F}, which returns the elements of In for which the boolean function F returns true. Here is a possible definition of Filter:
fun {Filter In F}
case In
of X|In2 then
if {F X} then X|{Filter In2 F}
else {Filter In2 F} end
else
nil
end
endExecuting the following:
{Show {Filter [5 1 2 4 0] fun {$ X} X>2 end}}displays
[5 4](We use the procedure Show, which displays the instantaneous value of its argument in Mozart’s emulator window. Unlike Browse, this output is not updated if the argument is subsequently bound.) So Filter works as expected in the case of a sequential execution when all the input values are available. Let us now explore the dataflow behaviour of Filter.
a) What happens when we execute the following?:
declare A
{Show {Filter [5 1 A 4 0] fun {$ X} X>2 end}}A that is not yet bound to a value. Remember that the case and if statements will suspend the thread in which they execute, until they can decide which alternative path to take.
b) What happens when we execute the following?:
declare Out A
thread Out={Filter [5 1 A 4 0] fun {$ X} X>2 end} end
{Show Out}Show displays its argument as it exists at the instant of the call. Several possible results can be displayed. Which and why? Is the Filter function deterministic? Why or why not?
c) What happens when we execute the following?:
declare Out A
thread Out={Filter [5 1 A 4 0] fun {$ X} X>2 end} end
{Delay 1000}
{Show Out}{Delay N} suspends its thread for at least N ms. During this time, other ready threads can be executed.
d) What happens when we execute the following?:
declare Out A
thread Out={Filter [5 1 A 4 0] fun {$ X} X>2 end} end
thread A=6 end
{Delay 1000}
{Show Out}a) Nothing is displayed because Filter is suspended waiting on A to become bound.
b) What gets displayed on my box is Out<optimized>. But when I use the Browser I see 5|_. Another possible value would _ if Show is executed before Filter. But even though there can be different values shown doesn’t mean that Filter itself is not deterministic. What’s not deterministic is the way threads are executed and Show is probably not part of the declarative model.
c) This displays 5|_<optimized>. So it seems that the calls to Show in b) that I got were all before the call to Filter.
d) This of course displays [5 6 4]. Filter can finish because A gets bound, and we are waiting long enough before calling Show.
Order-determining concurrency. Explain what happens when executing the following:
declare A B C D in
thread B=C+1 end
thread C=B+1 end
thread A=1 end
thread B=A+1 end
{Browse D}In what order are the threads created? In what order are the additions done? What is the final result? Compare with the following:
declare A B C D in
A=1
B=A+1
C=B+1
D=C+1
{Browse D}Here there is only one thread. In what order are the additions done? What is the final result? What do you conclude?
Of course both code snippets produce the same result, namely 4. And of course the threads in the first code example are executed in the same way as in the second. That’s because the threads have to wait for the variables they are using in the additions to become bound.
An what do I conclude? Well, that this kind of concurrency is declarative. At least that’s what I think I was supposed to answer :)
Order-determining concurrency. Explain what happens when executing the following:
declare A B C D in
thread B=C+1 end
thread C=B+1 end
thread A=1 end
thread B=A+1 end
{Browse D}In what order are the threads created? In what order are the additions done? What is the final result? Compare with the following:
declare A B C D in
A=1
B=A+1
C=B+1
D=C+1
{Browse D}Here there is only one thread. In what order are the additions done? What is the final result? What do you conclude?
Of course both code snippets produce the same result, namely 4. And of course the threads in the first code example are executed in the same way as in the second. That’s because the threads have to wait for the variables they are using in the additions to become bound.
An what do I conclude? Well, that this kind of concurrency is declarative. At least that’s what I think I was supposed to answer :)
Concurrent Fibonacci. Consider the following sequential definition of the Fibonacci function:
fun {Fib X}
if X=<2 then 1
else {Fib X-1}+{Fib X-2} end
endand compare it with the concurrent definition given in section 4.2.3. Run both on the Mozart system and compare their performance. How much faster is the sequential definition? How many threads are created by the concurrent call {Fib N} as a function if N?
For timing I used the following function. Even though it can only count in seconds, it’s enough for this purpose.
fun {Timer Fun Arg}
Before
in
Before={Time.time}
{Fun Arg _}
{Time.time}-Before
endFor N=30 the normal Fibonacci function took 1 second, the concurrent one 19. For N=40 the normal one took 289 seconds and the concurrent one made my computer swap so I stopped it.
The number of thread created should be in the same order as the number of function calls done, because every other function call is done in its own thread. As the number of function calls is exponential so is the number of threads. Of course this is quite a lame answer, but neither did I have skills nor the motivation to find an exact solution. Maybe Wikipedia can help?
Concurrent Fibonacci. Consider the following sequential definition of the Fibonacci function:
fun {Fib X}
if X=<2 then 1
else {Fib X-1}+{Fib X-2} end
endand compare it with the concurrent definition given in section 4.2.3. Run both on the Mozart system and compare their performance. How much faster is the sequential definition? How many threads are created by the concurrent call {Fib N} as a function if N?
For timing I used the following function. Even though it can only count in seconds, it’s enough for this purpose.
fun {Timer Fun Arg}
Before
in
Before={Time.time}
{Fun Arg _}
{Time.time}-Before
endFor N=30 the normal Fibonacci function took 1 second, the concurrent one 19. For N=40 the normal one took 289 seconds and the concurrent one made my computer swap so I stopped it.
The number of thread created should be in the same order as the number of function calls done, because every other function call is done in its own thread. As the number of function calls is exponential so is the number of threads. Of course this is quite a lame answer, but neither did I have skills nor the motivation to find an exact solution. Maybe Wikipedia can help?