UnsafeArrays provides stack-allocated pointer-based array views for Julia. This package is mainly intended as a workaround for Julia issue #14955 (non-allocating array views).
While the Julia compiler is able to elide heap-allocation of views in some cases, it cannot always do so. In some other cases, the relative cost of allocation and garbage collection of a even a large number of views is small. Especially in multi-threaded applications though, this cost can quickly become prohibitive and views must either be avoided (resulting in more lengthy and less readable code), or some form stack-allocated views must be used for decent scalability. UnsafeArrays aims to provide such a solution.
Example:
using Base.Threads, LinearAlgebra
function colnorms!(dest::AbstractVector, A::AbstractMatrix)
@threads for i in axes(A, 2)
dest[i] = norm(view(A, :, i))
end
dest
end
A = rand(50, 100000);
dest = similar(A, size(A, 2));
colnorms!(dest, A)
The above will run fine on a single thread, but scales badly on multiple
threads. Use the @uviews
macro provided by UnsafeArrays to replace A with an
UnsafeArray
within the scope of the macro. An UnsafeArray
is
stack-allocated, and so are all views of it, e.g. within colnorms!
:
using UnsafeArrays
@uviews A begin
colnorms!(dest, A)
end
@uviews
protects the original array A
from GC, so the above is safe as
long as the original array is not reallocated (via resize!
, etc.) while the
scope of @uviews
is active.
UnsafeArrays only supports bits types. If the element type of an array is not compatible, @uviews will simply use the original array.
UnsafeArrays also provides:
-
A non macro-variant
uviews()
-
A function
uview()
to directly get an unsafe view (with optional sub-indexing) of an array. -
The type
UnsafeArray
itself, instances can be constructed from a data pointer and array size. The data type must be a bits type.
When using uview()
and UnsafeArray
directly, the user is responsible for
preserving the memory accessed from garbage collection.