class HyperSeq
An object for performing batches of work in parallel with ordered output
does Iterable does Sequence
An HyperSeq is the intermediate object used when the operator hyper
is invoked on a Seq
. In general, it's not intended for direct consumption by the developer.
Methods
method iterator
method iterator(HyperSeq: --> Iterator)
Returns the underlying iterator.
method grep
method grep(HyperSeq: , *)
Applies grep
to the HyperSeq
similarly to how it would do it on a Seq.
my = (^10000).map(*²).hyper;.grep( * %% 3 ).say;# OUTPUT: «(0 9 36 81 144…»
When you use hyper
on a Seq
, this is the method that is actually called.
method map
method map(HyperSeq: , *)
Uses maps on the HyperSeq
, generally created by application of hyper
to a preexisting Seq
.
method invert
method invert(HyperSeq:)
Inverts the HyperSeq
created from a Seq
by .hyper
.
method hyper
method hyper(HyperSeq:)
Returns the object.
method race
method race(HyperSeq:)
Creates a RaceSeq
object out of the current one.
method serial
multi method serial(HyperSeq:)
Converts the object to a Seq
and returns it.
method is-lazy
method is-lazy(--> False )
Returns False
.
method sink
Defined as:
method sink(--> Nil)
Sinks the underlying data structure, producing any side effects.
Type Graph
Routines supplied by role Iterable
HyperSeq does role Iterable, which provides the following routines:
(Iterable) method iterator
Defined as:
method iterator(--> Iterator)
Method stub that ensures all classes doing the Iterable
role have a method iterator
.
It is supposed to return an Iterator.
say (1..10).iterator;
(Iterable) method flat
Defined as:
method flat(--> Iterable)
Returns another Iterable that flattens out all iterables that the first one returns.
For example
say (<a b>, 'c').elems; # OUTPUT: «2»say (<a b>, 'c').flat.elems; # OUTPUT: «3»
because <a b>
is a List and thus iterable, so (<a b>, 'c').flat
returns ('a', 'b', 'c')
, which has three elems.
Note that the flattening is recursive, so ((("a", "b"), "c"), "d").flat
returns ("a", "b", "c", "d")
, but it does not flatten itemized sublists:
say ($('a', 'b'), 'c').perl; # OUTPUT: «($("a", "b"), "c")»
(Iterable) method lazy
Defined as:
method lazy(--> Iterable)
Returns a lazy iterable wrapping the invocant.
say (1 ... 1000).is-lazy; # OUTPUT: «False»say (1 ... 1000).lazy.is-lazy; # OUTPUT: «True»
(Iterable) method hyper
Defined as:
method hyper(Int(Cool) : = 64, Int(Cool) : = 4)
Returns another Iterable that is potentially iterated in parallel, with a given batch size and degree of parallelism.
The order of elements is preserved.
say ([1..100].hyper.map().list);
Use hyper
in situations where it is OK to do the processing of items in parallel, and the output order should be kept relative to the input order. See race
for situations where items are processed in parallel and the output order does not matter.
Options degree and batch
The degree
option (short for "degree of parallelism") configures how many parallel workers should be started. To start 4 workers (e.g. to use at most 4 cores), pass :4degree
to the hyper
or race
method. Note that in some cases, choosing a degree higher than the available CPU cores can make sense, for example I/O bound work or latency-heavy tasks like web crawling. For CPU-bound work, however, it makes no sense to pick a number higher than the CPU core count.
The batch
size option configures the number of items sent to a given parallel worker at once. It allows for making a throughput/latency trade-off. If, for example, an operation is long-running per item, and you need the first results as soon as possible, set it to 1. That means every parallel worker gets 1 item to process at a time, and reports the result as soon as possible. In consequence, the overhead for inter-thread communication is maximized. In the other extreme, if you have 1000 items to process and 10 workers, and you give every worker a batch of 100 items, you will incur minimal overhead for dispatching the items, but you will only get the first results when 100 items are processed by the fastest worker (or, for hyper
, when the worker getting the first batch returns.) Also, if not all items take the same amount of time to process, you might run into the situation where some workers are already done and sit around without being able to help with the remaining work. In situations where not all items take the same time to process, and you don't want too much inter-thread communication overhead, picking a number somewhere in the middle makes sense. Your aim might be to keep all workers about evenly busy to make best use of the resources available.
You can also check out this blog post on the semantics of hyper and race
(Iterable) method race
Defined as:
method race(Int(Cool) : = 64, Int(Cool) : = 4 --> Iterable)
Returns another Iterable that is potentially iterated in parallel, with a given batch size and degree of parallelism (number of parallel workers).
Unlike hyper
, race
does not preserve the order of elements.
say ([1..100].race.map().list);
Use race in situations where it is OK to do the processing of items in parallel, and the output order does not matter. See hyper
for situations where you want items processed in parallel and the output order should be kept relative to the input order.
Blog post on the semantics of hyper and race
See hyper
for an explanation of :$batch
and :$degree
.
Routines supplied by role Sequence
HyperSeq does role Sequence, which provides the following routines:
(Sequence) method Str
multi method Str(::?CLASS:)
Stringifies the cached sequence.
(Sequence) method Stringy
multi method Stringy(::?CLASS:)
Calls .Stringy
on the cached sequence.
(Sequence) method Numeric
method Numeric(::?CLASS:)
Returns the number of elements in the cached sequence.
(Sequence) method AT-POS
multi method AT-POS(::?CLASS: Int )multi method AT-POS(::?CLASS: int )
Returns the element at position $idx
in the cached sequence.
(Sequence) method EXISTS-POS
multi method EXISTS-POS(::?CLASS: Int )multi method EXISTS-POS(::?CLASS: int )
Returns a Bool
indicating whether there is an element at position $idx
in the cached sequence.
(Sequence) method eager
method eager(::?CLASS: --> List)
Returns an eagerly evaluated List based on the invocant sequence, and marks it as consumed. If called on an already consumed Seq
, throws an error of type X::Seq::Consumed.
my = lazy 1..5;say .is-lazy; # OUTPUT: «True»say .eager; # OUTPUT: «(1 2 3 4 5)»say .eager;CATCH# OUTPUT: «Throws exception if already consumed»
(Sequence) method fmt
method fmt( = '%s', = ' ' --> Str)
(Sequence) method gist
multi method gist(::?CLASS:)
Returns the gist of the cached sequence.
Routines supplied by role PositionalBindFailover
HyperSeq does role PositionalBindFailover, which provides the following routines:
(PositionalBindFailover) method cache
method cache(PositionalBindFailover: --> List)
Returns a List based on the iterator
method, and caches it. Subsequent calls to cache
always return the same List
object.
(PositionalBindFailover) method list
method list(PositionalBindFailover: --> List)
Returns a List based on the iterator
method without caching it.
(PositionalBindFailover) method iterator
method iterator(PositionalBindFailover:)
This method stub ensure that a class implementing role PositionalBindFailover
provides an iterator
method.