Reagents.jl is still work-in-progress.
Catalysts
A catalyst can be introduced by Reagents.dissolve
for expressing a rule under which a certain set of reactions can happen.
As a motivating example, consider writing a program with multiple channels:
function test_catalyst_idea()
send1, receive1 = Reagents.channel(Int, Nothing)
send2, receive2 = Reagents.channel(Char, Nothing)
sendall, receiveall = Reagents.channel(Tuple{Int,Char}, Nothing)
Suppose we want to combine the items from the first and the second channels into the third channel. In principle, this can be expressed as a "background" task repeatedly executing such reaction ("catalyst"):
background_task = @async begin
catalyst = (receive1 & receive2) ⨟ sendall
while true
catalyst()
end
end
The above background_task
transfers the items that are available in receive1
and receive2
to to sendall
.
@sync begin
@async send1(1)
@async send2('a')
@test receiveall() == (1, 'a')
end
Since the background_task
keeps helping the reactions, we can invoke the same set of reactions multiple times:
@sync begin
@async send1(2)
@async send2('b')
@test receiveall() == (2, 'b')
end
end
(Aside: Note the use of unstructured concurrency for implementing the background_task
. The error happening inside of this task cannot be noticed at relevant locations. This is another motivation for avoiding this style.)
A downside of the approach above is that it invokes many context switches between tasks. For more efficient and direct style of expressing the idea, we can use Reagents.dissolve
.
Let us re-implement the above example:
function test_zip2()
send1, receive1 = Reagents.channel(Int, Nothing)
send2, receive2 = Reagents.channel(Char, Nothing)
sendall, receiveall = Reagents.channel(Tuple{Int,Char}, Nothing)
If the items are aviable in receive1
and receive2
, the catalyst
reagent automatically tries to pass them to sendall
:
catalyst = (receive1 & receive2) ⨟ sendall
Reagents.dissolve(catalyst)
Just like the background_task
-based example above, the catalyst
helps invoking the matched set of reactions:
@sync begin
@async send1(1)
@async send2('a')
@test receiveall() == (1, 'a')
end
Since the catalyst
will not be "used up," we can invoke the same reaction multiple times:
@sync begin
@async send1(2)
@async send2('b')
@test receiveall() == (2, 'b')
end
end
This page was generated using Literate.jl.