Files
comp4958/lectures/05/notes.ex
T
2026-10-08 20:59:37 -07:00

72 lines
2.6 KiB
Elixir

# register a process that can store key, value pairs
Registry.start_link(name: R, keys: :duplicate)
# register(register_name, key, value)
Register.register(R, "hello", "world")
Register.lookup(R, "hello")
# here we can associate a name, with a process ID
# can allow us to dynamically start any number of Workers
Registry.register(R, {Counter.Worker, "c1"})
f = fn (k, v) -> spawn(fn -> Registry.register(R, k, v); Process.sleep(30_000) end) end
pid = f.(:abc, 1)
Registry.keys(R, pid) # get all the keys for a PID -> [:abc]
Process.alive?(pid) # once dead i.e. returns -> false then:
Registry.keys(R, pid) # the process ID will be gone, -> [] not [:abc]
# Using our dynamic_counters implementation we have a counter server
# that is fault tolerant, i.e. if a worker dies, they will restart
DynamicSupervisor.start_child(Counter.DynamicSupervisor, {Counter.Worker, "c1"})
# -> {:ok, #PID<0.147.0>}
{_, pid} = v
# -> {:ok, #PID<0.147.0>}
Counter.Worker.inc("c1")
# -> :ok
Counter.Worker.inc("c1")
# -> :ok
Counter.Worker.value("c1")
# -> 2
# we can crash and see it restarts
Counter.Worker.inc("c1", "hello")
# -> :ok
# 10:04:25.932 [error] GenServer {Counter.Registry, {Counter.Worker, "c1"}} terminating
# ** (ArithmeticError) bad argument in arithmetic expression
# :erlang.+(2, "hello")
# (dynamic_counters 0.1.0) lib/dynamic_counters/worker.ex:37: Counter.Worker.handle_cast/2
# (stdlib 6.2.2.5) gen_server.erl:2371: :gen_server.try_handle_cast/3
# (stdlib 6.2.2.5) gen_server.erl:2433: :gen_server.handle_msg/6
# (stdlib 6.2.2.5) proc_lib.erl:329: :proc_lib.init_p_do_apply/3
# Last message: {:"$gen_cast", {:inc, "hello"}}
# State: 2
Counter.Worker.value("c1")
# -> 0 has restarted without retaining state
Enum.each(1..100_000, fn n -> DynamicSupervisor.start_child(Counter.DynamicSupervisor, {Counter.Worker, "d#{n}"}) end )
# -> :ok
Enum.each(1..100_000, fn n -> Counter.Worker.inc("d#{n}", n) end)
# -> :ok
Enum.map(1..10, fn n -> Counter.Worker.value("d#{n}") end)
# -> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
### Erlang Term Store
t = :ets.new(T, [])
# you can insert tuples of any number of elements, but typically just a key, value pair
# by default you cannot have duplicate keys
:ets.insert(t, {:a, 1})
:ets.lookup(t, :a) # -> [a: 1] lookup only matches the first element of a tuple
:ets.insert(t, {"hello", 2, :abc})
:ets.tab2list(t) # -> [{a: 2}, {"hello, 2, :abc}]
:ets.insert(t, {"world", 3, :xyz})
:ets.match_object(t, {"hello", :_, :_}) # -> [{"hello", 2, :abc}]
:ets.new(T, [:named_table, :public]) # can also use a named table and not need to assign to something like t
:ets.insert(T, {:abc, 123})
:ets.lookup(T, :abc);
System.schedulers_online()