Advanced 2
Mix.install([
{:vega_lite, "~> 0.1.10"},
{:kino_vega_lite, "~> 0.1.13"}
])
Forberedelse
Dette trins opave er:
-
Åben igen
index.livemd
(fra https://github.com/aslakjohansen/livebook-demos) i Livebook, og evaluér den sidste celle om nødvendigt. -
Klik dig igennem følgende demoer:
- Primitive concurrency
Øvelse
Denne øvelse tager udgangspunkt i Fibonacci sekvensen. Dette er en sekvens af tal der er defineret ved:
$ fib(n) = \begin{cases}
0, & \text{\color{violet} for n=0} \\
n, & \text{\color{violet} for n=1} \\
fib(n-1)+fib(n-2), & \text{\color{violet} for n>1} \\
\end{cases} $
Denne sekvens viser sig ofte i naturen, og nogle har brugt den i deres musik.
Her er en implementation der kan udregne det $n$’te tal i sekvensen:
defmodule Fibonacci do
def index(0), do: 0
def index(1), do: 1
def index(n) when is_integer(n) and n>1 do
index(n-1) + index(n-2)
end
end
De første 40 Fibonacci tal er:
0..39 |> Enum.map(&Fibonacci.index/1)
Øvelsen er, for 1000 værdier for $n$, at finde de matchende tal i fibonacci sekvensen. Her har vi de 1000 værdier for $n$:
ns =
1..1_000
|> Enum.map(fn _ -> Enum.random(1..39) end)
Den naive løsning er at udregne dette sekventielt med følgende kode:
Enum.map(ns, &Fibonacci.index/1)
Denne løsning vil dog kun udnytte én af din maskines processor kerner. Ved at formulere en løsning concurrently vil vi kunne udnytte de kerner vi måtte have. Det er din opgave implementere en sådan løsning ved at benytte fork-join teknikken fra den notebook du klikkede dig igennem i øverst på denne side.
Du kan med fordel bygge videre på følgende kode:
defmodule Concurrent do
def map(elements, fun) do
# fork
res = Enum.map(elements, fn element -> process(element, fun) end)
# join
end
defp process(element, fun) do
fun.(element)
end
end
Concurrent.map(ns, &Fibonacci.index/1)
Næste trin …
Når du er færdig går du til næste øvelse her.