@@ -109,8 +109,7 @@ defmodule Registry do
109
109
110
110
In this example, we will also set the number of partitions to the number of
111
111
schedulers online, which will make the registry more performant on highly
112
- concurrent environments as each partition will spawn a new process, allowing
113
- dispatching to happen in parallel:
112
+ concurrent environments:
114
113
115
114
{:ok, _} = Registry.start_link(keys: :duplicate, name: Registry.PubSubTest,
116
115
partitions: System.schedulers_online)
@@ -362,17 +361,16 @@ defmodule Registry do
362
361
associated to the pid. If there are no entries for the given key,
363
362
the callback is never invoked.
364
363
365
- If the registry is not partitioned, the callback is invoked in the process
366
- that calls `dispatch/3`. If the registry is partitioned, the callback is
367
- invoked concurrently per partition by starting a task linked to the
368
- caller. The callback, however, is only invoked if there are entries for that
369
- partition.
364
+ If the registry is partitioned, the callback is invoked multiple times
365
+ per partition. If the registry is partitioned and `parallel: true` is
366
+ given as an option, the dispatching happens in parallel. In both cases,
367
+ the callback is only invoked if there are entries for that partition.
370
368
371
369
See the module documentation for examples of using the `dispatch/3`
372
370
function for building custom dispatching or a pubsub system.
373
371
"""
374
- @ spec dispatch ( registry , key , ( entries :: [ { pid , value } ] -> term ) ) :: :ok
375
- def dispatch ( registry , key , mfa_or_fun )
372
+ @ spec dispatch ( registry , key , ( entries :: [ { pid , value } ] -> term ) , keyword ) :: :ok
373
+ def dispatch ( registry , key , mfa_or_fun , opts \\ [ ] )
376
374
when is_atom ( registry ) and is_function ( mfa_or_fun , 1 )
377
375
when is_atom ( registry ) and tuple_size ( mfa_or_fun ) == 3 do
378
376
case key_info! ( registry ) do
@@ -386,17 +384,33 @@ defmodule Registry do
386
384
|> safe_lookup_second ( key )
387
385
|> apply_non_empty_to_mfa_or_fun ( mfa_or_fun )
388
386
{ :duplicate , partitions , _ } ->
389
- registry
390
- |> dispatch_task ( key , mfa_or_fun , partitions )
391
- |> Enum . each ( & Task . await ( & 1 , :infinity ) )
387
+ if Keyword . get ( opts , :parallel , false ) do
388
+ registry
389
+ |> dispatch_parallel ( key , mfa_or_fun , partitions )
390
+ |> Enum . each ( & Task . await ( & 1 , :infinity ) )
391
+ else
392
+ dispatch_serial ( registry , key , mfa_or_fun , partitions )
393
+ end
392
394
end
393
395
:ok
394
396
end
395
397
396
- defp dispatch_task ( _registry , _key , _mfa_or_fun , 0 ) do
398
+ defp dispatch_serial ( _registry , _key , _mfa_or_fun , 0 ) do
399
+ :ok
400
+ end
401
+ defp dispatch_serial ( registry , key , mfa_or_fun , partition ) do
402
+ partition = partition - 1
403
+ registry
404
+ |> key_ets! ( partition )
405
+ |> safe_lookup_second ( key )
406
+ |> apply_non_empty_to_mfa_or_fun ( mfa_or_fun )
407
+ dispatch_serial ( registry , key , mfa_or_fun , partition )
408
+ end
409
+
410
+ defp dispatch_parallel ( _registry , _key , _mfa_or_fun , 0 ) do
397
411
[ ]
398
412
end
399
- defp dispatch_task ( registry , key , mfa_or_fun , partition ) do
413
+ defp dispatch_parallel ( registry , key , mfa_or_fun , partition ) do
400
414
partition = partition - 1
401
415
parent = self ( )
402
416
task = Task . async ( fn ->
@@ -407,7 +421,7 @@ defmodule Registry do
407
421
Process . unlink ( parent )
408
422
:ok
409
423
end )
410
- [ task | dispatch_task ( registry , key , mfa_or_fun , partition ) ]
424
+ [ task | dispatch_parallel ( registry , key , mfa_or_fun , partition ) ]
411
425
end
412
426
413
427
defp apply_non_empty_to_mfa_or_fun ( [ ] , _mfa_or_fun ) do
0 commit comments