Julio.jl is still work-in-progress.
API
JulioJulio.EventsJulio.LockJulio.PromiseJulio.cancel!Julio.channelJulio.checkpointJulio.oncancelJulio.openJulio.queueJulio.selectJulio.shieldJulio.spawn!Julio.stackJulio.withtaskgroupJulio.withtimeoutJulio.yield
Julio.Events — ConstantJulio.Events.f(args...; kwargs...)Julio.Events.f(args...; kwargs...) creates an event (i.e., an object describing how to execute f(args...; kwargs...)) that can be passed to Julio.select.
Example
Unlike (f, args...) syntax that is also accepted by Julio.select, Events.f(args...) may have some states. For example, Events.sleep(seconds) sets the timeout at the time the event is created and not when it is passed to Julio.select:
julia> using Julio: Julio, Events
julia> Julio.withtaskgroup() do tg
Julio.spawn!(tg) do
ev = Events.sleep(0.1) # countdown starts now
while true
Julio.select(
ev => Returns(true), # eventually this event wins
Events.sleep(0) => Returns(false),
) && break
end
end
end;Julio.Lock — TypeJulio.Lock()Creates a reentrant lock.
Julio.Promise — TypeJulio.Promise{T}()
Julio.Promise()Create a promise.
A value of type T (or Any if unspecified) can be set once by put!. Calling fetch blocks until put! is called.
The indexing notation p[] can be used as a synonym for put! and fetch.
Example
julia> using Julio
julia> p = Julio.Promise();
julia> p[] = 111;
julia> p[]
111
julia> Julio.withtaskgroup() do tg
p = Julio.Promise{Int}()
Julio.spawn!(tg) do
p[] = 222
end
p[]
end
222Julio.cancel! — FunctionJulio.cancel!(tg)
Julio.cancel!(scope)
Julio.cancel!(handle)Cancel a task group tg or cancellation scope scope.
It can also be used for revoking the handle returned from Julio.oncancel.
Julio.channel — FunctionJulio.channel(T::Type = Any) -> (send_endpoint, receive_endpoint)Julio.channel creates a unbuffered channel and return a pair of send_endpoint and receive_endpoint.
Following methods are supported by the channel:
put!(send_endpoint, item::T)
Julio.tryput!(send_endpoint, item::T) -> success::Bool
take!(receive_endpoint) -> item::T
Julio.maybetake!(receive_endpoint) -> Some(item) or nothing
close(send_endpoint)
close(receive_endpoint)Julio.checkpoint — FunctionJulio.checkpoint()Check for cancellation signal. It throws when cancellation is required.
Julio.oncancel — FunctionJulio.oncancel(f, args...) -> handleRegister a cancellation callback f and its arguments args to the current cancellation scope. This callback is triggered via Julio.cancel!(tg) or Julio.cancel!(scope).
The registered callback can be removed by Julio.cancel!(handle).
See also: Julio.cancel!.
Example
julia> using Julio
julia> Julio.withtaskgroup() do tg
Julio.spawn!(tg) do
ch = Channel() # non Julio API
Julio.oncancel(close, ch) # close the channel on cancellation
try
take!(ch) # blocks forever
catch
isopen(ch) && rethrow() # ignore the exception due to `close`
end
end
Julio.cancel!(tg)
end;Julio.open — FunctionJulio.open(io::IO; close = false) -> wrapped_io::IOWrap an IO object into a new IO that is usable via Julio's synchronization API.
Julio.open(x::AbstractCommand, args...)
Julio.open(x::AbstractString, args...)Synonym of Julio.open(open(x, args...); close = true).
Julio.open(f, x, args...)A shorthand for
resource = Julio.open(x, args...)
try
f(resource)
finally
close(resource)
endJulio.queue — FunctionJulio.queue(T::Type = Any) -> (send_endpoint, receive_endpoint)See Julio.channel.
Julio.select — FunctionJulio.select(ev₁, ev₂, ..., evₙ) -> ansᵢSelect and execute one and only one event evᵢ (1 ≤ i ≤ n) and return its result ansᵢ.
An even has the following format
(f, args...)
(f, args...) => g
Julio.Events.f(args...; kwargs...)
Julio.Events.f(args...; kwargs...) => gwhere f is a function such as take! and put!, args are their arguments, kwargs are the named arguments, and g is a unary function that receives the output of (f, args...) or Julio.Events.f(args...; kwargs...). If g is not specified, identity is used instead.
Examples
using Julio: Events
Julio.select(
(Julio.tryput!, send_endpoint, item),
(take!, receive_endpoint) => item -> begin
println("Got: ", item)
end,
Event.put!(another_send_endpoint, item),
Event.readline(io; keep = true) => line -> begin
println("Read line: ", line)
end,
)Julio.shield — FunctionJulio.shield(f)Run f in a special scope where the cancellation signals are blocked.
Julio.spawn! — FunctionJulio.spawn!(f, tg, args...) -> taskRun a function f with arguments args inside a task managed by the task group tg.
See Julio.withtaskgroup.
Example
julia> using Julio
julia> send_endpoint, receive_endpoint = Julio.queue();
julia> Julio.withtaskgroup() do tg
Julio.spawn!(tg, 111) do x
put!(send_endpoint, x)
end
Julio.spawn!(tg) do
@show take!(receive_endpoint)
end
end;
take!(receive_endpoint) = 111Julio.stack — FunctionJulio.stack(T::Type = Any) -> (send_endpoint, receive_endpoint)See Julio.channel.
Julio.withtaskgroup — FunctionJulio.withtaskgroup(f) -> ansCreate a task group tg and pass it to the function f of the form tg -> ans.
See Julio.spawn!.
Example
julia> using Julio
julia> Julio.withtaskgroup() do tg
Julio.spawn!(tg) do
println("hello")
end
end;
helloJulio.withtimeout — FunctionJulio.withtimeout(f, seconds) -> Some(ans) or nothingRun f() with timeout seconds. If it finishes with output value ans before the timeout, return Some(ans). Return nothing otherwise.
Note that blocking operations must use Julio API for automatic cancellation; Julio.sleep instead of sleep, read(Julio.open(io)) instead of read(io), and so on. Use Julio. Non-Julio API can be cancelled using Julio.oncancel.
Example
julia> using Julio
julia> Julio.withtimeout(0.1) do
Julio.sleep(60)
end === nothing # too slow
true
julia> Julio.withtimeout(60) do
Julio.sleep(0.1)
end === Some(nothing) # success
trueJulio.yield — FunctionJulio.yield()A shorthand for Julio.checkpoint(); yield().