Recyclers.jl
Recyclers — ModuleRecyclers
Recyclers.jl is a set of tools for implementing memory reuse patterns in multi-tasking Julia programs.
julia> using Recyclers
julia> recycler = Recyclers.CentralizedRecycler(() -> zeros(3));
julia> xs = Recyclers.get!(recycler) # get a cached object or create a new one
3-element Vector{Float64}:
0.0
0.0
0.0
julia> Recyclers.recycle!(recycler, xs) # returns `true` if recycled
trueConstructors
Recyclers.AbstractRecycler — TypeAbstractRecycler{T}A high-level object recycling interface. It pairs an AbstractCache{T} with an object factory function.
A concrete subtype Recycler{T} of AbstractRecycler{T} (e.g., ShardedRecycler) have the following constructor methods:
Recycler{T}(factory)
Recycler(factory)where factory is a zero-argument function that returns an object of type T and objects is an iterable with elements of type T. The constructor of each Recycler subtype may accept additional keyword arguments.
factory function contracts. The program author calling Recycler constructor must verify that invocation of factory function on arbitrary worker thread does not introduce any concurrency problems including data races. When used with the method Recycler{T}(factory), the factory function must return an object of type T (where T does not have to be concrete; i.e., T = Any always works). A run-time error is thrown if factory is called and return an object that is not of type T. When used with the method Recycler(factory), the factory function must be type-stable in the sense that objects o1 = factory() and o2 = factory() obtained in arbitrary calling contexts must satisfy typeof(o1) === typeof(o2). With any constructor methods, changes in the return type of factory function after construction of the recycler may result in run-time error.
Supported methods:
Recyclers.ShardedRecycler — TypeRecyclers.ShardedRecycler{T}(factory; [limit])
Recyclers.ShardedRecycler(factory; [limit])Create a sharded object recycler. See AbstractRecycler for more information on the constructor and supported methods.
The factory function must not introduce any concurrency problems. See see AbstractRecycler for more information.
ShardedRecycler uses a stack of size bounded by limit for each worker thread. The keyword argument limit must be a positive integer less than typemax(UInt) or Inf.
Recyclers.CentralizedRecycler — TypeRecyclers.CentralizedRecycler{T}(factory)
Recyclers.CentralizedRecycler(factory)Create a centralized object recycler. See AbstractRecycler for more information on the constructor and supported methods.
The factory function must not introduce any concurrency problems. See see AbstractRecycler for more information.
CentralizedRecycler uses a lock-free unbounded stack. It supports thread-safe empty!(recycler) method.
Recyclers.@global — MacroRecyclers.@global recycler_name = make_recyclerDeclare a global constant named recycler_name (a symbol) which holds a recycler created by make_recycler (an expression).
The recycler is re-initialized (using Recyclers.unsafe_init!) while importing the package in which recycler_name is defined.
If it can be ensured that no tasks are requiring to access recycler_name during exit, it may be a good idea to call Recyclers.unsafe_destroy! or Recyclers.unsafe_empty! via atexit.
Example:
Recyclers.@global INTS_RECYCLER = Recyclers.ShardedRecycler(() -> Vector{Int}(undef, 100))
atexit() do
Recyclers.unsafe_destroy!(INTS_RECYCLER)
endRecyclers.AbstractCache — TypeAbstractCache{T}A low-level object recycling interface.
Supported methods:
Recyclers.get!(factory, cache)Recyclers.maybeget!(cache)Recyclers.recycle!(cache, object)Recyclers.recycling!(body, factory, cache)Recyclers.unsafe_empty!(cache)
See also: AbstractRecycler
Recycling objects
Recyclers.get! — FunctionRecyclers.get!(recycler::AbstractRecycler{T}) -> object::T
Recyclers.get!(factory, cache::AbstractCache{T}) -> object::TObtain cached object of type T or create a new one using factory().
The factory function must not introduce any concurrency problems. See see AbstractRecycler for more information.
Recyclers.maybeget! — FunctionRecyclers.maybeget!(recycler::AbstractRecycler{T}) -> Some{T}(object) or nothing
Recyclers.maybeget!(cache::AbstractCache{T}) -> Some{T}(object) or nothingObtain cached object wrapped in a Some{T} or nothing.
Recyclers.recycle! — FunctionRecyclers.recycle!(recycler::AbstractRecycler{T}), object::T) -> isrecycled::Bool
Recyclers.recycle!(cache::AbstractCache{T}), object::T) -> isrecycled::BoolTry to recycle a object and return true if and only if the object is recycled.
Recyclers.recycling! — FunctionRecyclers.recycle!(body, recycler::AbstractRecycler{T})) -> result
Recyclers.recycle!(body, factory, cache::AbstractCache{T})) -> resultCall a single-argument function body with a object, try to recycle the object, and then return the result returned from body.
The object is not recycled if body throws since the invariance of object may not hold any more.
Managing recyclers
Recyclers.unsafe_empty! — FunctionRecyclers.unsafe_empty!(recycler::AbstractRecycler) -> recycler
Recyclers.unsafe_empty!(cache::AbstractCache) -> cacheEmpty a cache or underlying cache of a recycler to help garbage collecting pooled objects. It is unsafe in the sense that there is no protection against accesses from other tasks; i.e., the programmer calling this function is responsible for ensuring that no concurrent tasks are accessing recycler.
Recyclers.unsafe_init! — FunctionRecyclers.unsafe_init!(recycler) -> recyclerRe-initialize recycler. It is unsafe in the sense that there is no protection against accesses from other tasks; i.e., the programmer calling this function is responsible for ensuring that no concurrent tasks are accessing recycler.
Recyclers.unsafe_destroy! — FunctionRecyclers.unsafe_destroy!(recycler::AbstractRecycler) -> recycler
Recyclers.unsafe_destroy!(cache::AbstractCache) -> cacheDestroy a cache or underlying cache of a recycler, typically to minimize serialized global cache. The cache and recycler cannot be used unless Recyclers.unsafe_init! is called first. It is unsafe in the sense that there is no protection against accesses from other tasks; i.e., the programmer calling this function is responsible for ensuring that no concurrent tasks are accessing recycler.