Recyclers.jl

RecyclersModule

Recyclers

Dev CI Aqua QA

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
true
source

Constructors

Recyclers.AbstractRecyclerType
AbstractRecycler{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:

source
Recyclers.ShardedRecyclerType
Recyclers.ShardedRecycler{T}(factory; [limit])
Recyclers.ShardedRecycler(factory; [limit])

Create a sharded object recycler. See AbstractRecycler for more information on the constructor and supported methods.

Warning

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.

source
Recyclers.CentralizedRecyclerType
Recyclers.CentralizedRecycler{T}(factory)
Recyclers.CentralizedRecycler(factory)

Create a centralized object recycler. See AbstractRecycler for more information on the constructor and supported methods.

Warning

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.

source
Recyclers.@globalMacro
Recyclers.@global recycler_name = make_recycler

Declare 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)
end
source

Recycling objects

Recyclers.get!Function
Recyclers.get!(recycler::AbstractRecycler{T}) -> object::T
Recyclers.get!(factory, cache::AbstractCache{T}) -> object::T

Obtain cached object of type T or create a new one using factory().

Warning

The factory function must not introduce any concurrency problems. See see AbstractRecycler for more information.

source
Recyclers.maybeget!Function
Recyclers.maybeget!(recycler::AbstractRecycler{T}) -> Some{T}(object) or nothing
Recyclers.maybeget!(cache::AbstractCache{T}) -> Some{T}(object) or nothing

Obtain cached object wrapped in a Some{T} or nothing.

source
Recyclers.recycle!Function
Recyclers.recycle!(recycler::AbstractRecycler{T}), object::T) -> isrecycled::Bool
Recyclers.recycle!(cache::AbstractCache{T}), object::T) -> isrecycled::Bool

Try to recycle a object and return true if and only if the object is recycled.

source
Recyclers.recycling!Function
Recyclers.recycle!(body, recycler::AbstractRecycler{T})) -> result
Recyclers.recycle!(body, factory, cache::AbstractCache{T})) -> result

Call 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.

source

Managing recyclers

Recyclers.unsafe_empty!Function
Recyclers.unsafe_empty!(recycler::AbstractRecycler) -> recycler
Recyclers.unsafe_empty!(cache::AbstractCache) -> cache

Empty 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.

source
Recyclers.unsafe_init!Function
Recyclers.unsafe_init!(recycler) -> recycler

Re-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.

source
Recyclers.unsafe_destroy!Function
Recyclers.unsafe_destroy!(recycler::AbstractRecycler) -> recycler
Recyclers.unsafe_destroy!(cache::AbstractCache) -> cache

Destroy 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.

source