-
-
Notifications
You must be signed in to change notification settings - Fork 5.7k
Open
Description
I have this little Future utility that I've found really useful in a number of projects/packages:
mutable struct Future{T}
const notify::Threads.Condition
@atomic set::Int8 # if 0, result is undefined, 1 means result is T, 2 means result is an exception
result::Union{Exception, T} # undefined initially
Future{T}() where {T} = new{T}(Threads.Condition(), 0)
end
function Future{T}(f)
fut = Future{T}()
Threads.@spawn try
notify(fut, f())
catch e
notify(fut, capture(e))
end
return fut
end
function Base.wait(f::Future{T}) where {T}
set = @atomic f.set
set == 1 && return f.result::T
set == 2 && throw(f.result::Exception)
lock(f.notify) # acquire barrier
try
set = f.set
set == 1 && return f.result::T
set == 2 && throw(f.result::Exception)
wait(f.notify)
finally
unlock(f.notify) # release barrier
end
if f.set == 1
return f.result::T
else
@assert isdefined(f, :result)
throw(f.result::Exception)
end
end
capture(e::Exception) = CapturedException(e, Base.backtrace())
Base.notify(f::Future{Nothing}) = notify(f, nothing)
function Base.notify(f::Future{T}, x) where {T}
lock(f.notify) # acquire barrier
try
if f.set == Int8(0)
if x isa Exception
set = Int8(2)
f.result = x
else
set = Int8(1)
f.result = convert(T, x)
end
@atomic :release f.set = set
notify(f.notify)
end
finally
unlock(f.notify)
end
nothing
endIt's essentially a mix between a Threads.Event and a single-value Channel{T}. Personally, I like the simplicity of just wait and notify, while also keeping the exception-handling of channels.
I know we're starting to accumulate a variety of "flavors" of these kinds of definitions in Base, so if we feel like it'd be "one extra thing" I'll probably put it in ConcurrentUtilities.jl, but I figured it's general enough and simple enough, it might be worth including in Base directly.
For example usage, you end up with really convenient syntax like:
function do_foo_async()
return Future{Result}() do
compute_result_async()
end
endMetadata
Metadata
Assignees
Labels
No labels