Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/vrurg/raku-async-workers
Manager for threaded asynchronous workers
https://github.com/vrurg/raku-async-workers
Last synced: 2 months ago
JSON representation
Manager for threaded asynchronous workers
- Host: GitHub
- URL: https://github.com/vrurg/raku-async-workers
- Owner: vrurg
- License: artistic-2.0
- Created: 2019-05-10T22:25:57.000Z (over 5 years ago)
- Default Branch: main
- Last Pushed: 2023-12-17T04:13:52.000Z (about 1 year ago)
- Last Synced: 2023-12-17T05:21:51.061Z (about 1 year ago)
- Language: Raku
- Size: 90.8 KB
- Stars: 3
- Watchers: 2
- Forks: 1
- Open Issues: 1
-
Metadata Files:
- Readme: README.html
- Changelog: ChangeLog.html
- License: LICENSE
Awesome Lists containing this project
README
README
hr,
img {
box-sizing: content-box
}
body::after,
body::before,
hr::after,
hr::before {
display: table;
content: ""
}
a,
a:not([href]) {
text-decoration: none
}hr,
svg:not(:root) {
overflow: hidden
}img,
table tr {
background-color: #fff
}pre,
table {
overflow: auto
}dl,
dl dt,
hr,
pre code,
pre>code,
td,
th {
padding: 0
}input,
pre code {
overflow: visible
}pre,
pre code {
word-wrap: normal
}body {
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
color: #333;
font-family: "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
font-size: 16px;
line-height: 1.5;
word-wrap: break-word;
width: 820px;
margin: 2em auto;
}a {
background-color: transparent;
-webkit-text-decoration-skip: objects;
color: #4078c0
}a:active,
a:hover {
outline-width: 0;
text-decoration: underline
}h1 {
margin: .67em 0
}img {
border-style: none;
max-width: 100%
}h1,
h2 {
padding-bottom: .3em;
border-bottom: 1px solid #eee
}input {
font: inherit;
margin: 0;
font-family: inherit;
font-size: inherit;
line-height: inherit
}* {
box-sizing: border-box
}strong {
font-weight: 600
}body::after,
hr::after {
clear: both
}table {
border-spacing: 0;
border-collapse: collapse;
display: block;
width: 100%
}blockquote {
margin: 0;
padding: 0 1em;
color: #777;
border-left: .25em solid #ddd
}ol ol,
ul ol {
list-style-type: lower-roman
}ol ol ol,
ol ul ol,
ul ol ol,
ul ul ol {
list-style-type: lower-alpha
}dd {
margin-left: 0
}code {
font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace
}pre {
font: 12px Consolas, "Liberation Mono", Menlo, Courier, monospace
}input {
-webkit-font-feature-settings: "liga" 0;
font-feature-settings: "liga" 0
}body>:first-child {
margin-top: 0!important
}body>:last-child {
margin-bottom: 0!important
}a:not([href]) {
color: inherit
}blockquote,
dl,
ol,
p,
pre,
table,
ul {
margin-top: 0;
margin-bottom: 16px
}hr {
background: #e7e7e7;
height: .25em;
margin: 24px 0;
border: 0
}blockquote>:first-child {
margin-top: 0
}blockquote>:last-child {
margin-bottom: 0
}h1,
h2,
h3,
h4,
h5,
h6 {
margin-top: 24px;
margin-bottom: 16px;
font-weight: 600;
line-height: 1.25
}dl dt,
table th {
font-weight: 700
}h1 code,
h1 tt,
h2 code,
h2 tt,
h3 code,
h3 tt,
h4 code,
h4 tt,
h5 code,
h5 tt,
h6 code,
h6 tt {
font-size: inherit
}h1 {
font-size: 2em
}h2 {
font-size: 1.5em
}h3 {
font-size: 1.25em
}h4 {
font-size: 1em
}h5 {
font-size: .875em
}h6 {
font-size: .85em;
color: #777
}ol,
ul {
padding-left: 2em
}ol ol,
ol ul,
ul ol,
ul ul {
margin-top: 0;
margin-bottom: 0
}li>p {
margin-top: 16px
}li+li {
margin-top: .25em
}dl dt {
margin-top: 16px;
font-size: 1em;
font-style: italic
}dl dd {
padding: 0 16px;
margin-bottom: 16px
}table td,
table th {
padding: 6px 13px;
border: 1px solid #ddd
}table tr {
border-top: 1px solid #ccc
}table tr:nth-child(2n) {
background-color: #f8f8f8
}code {
padding: .2em 0;
margin: 0;
font-size: 85%;
background-color: rgba(0, 0, 0, .04);
border-radius: 3px
}code::after,
code::before {
letter-spacing: -.2em;
content: "\00a0"
}pre>code {
margin: 0;
font-size: 100%;
word-break: normal;
white-space: pre;
background: 0 0;
border: 0
}pre {
padding: 16px;
font-size: 85%;
line-height: 1.45;
background-color: #f7f7f7;
border-radius: 3px
}pre code {
display: inline;
max-width: auto;
margin: 0;
line-height: inherit;
background-color: transparent;
border: 0
}pre code::after,
pre code::before {
content: normal
}kbd {
display: inline-block;
padding: 3px 5px;
font: 11px Consolas, "Liberation Mono", Menlo, Courier, monospace;
line-height: 10px;
color: #555;
vertical-align: middle;
background-color: #fcfcfc;
border: 1px solid #ccc;
border-bottom-color: #bbb;
border-radius: 3px;
box-shadow: inset 0 -1px 0 #bbb
}hr {
border-bottom-color: #eee
}
.toc-level-1 .toc-text { padding-left: 1.5em; }
.toc-level-2 .toc-text { padding-left: 2.5em; }
.toc-level-3 .toc-text { padding-left: 3.5em; }
.toc-level-4 .toc-text { padding-left: 4.5em; }
.toc-level-5 .toc-text { padding-left: 5.5em; }
#TOC * { border-width: 0; }
li > p { margin: inherit; }
li > .pod-block-code { margin-top: 16px; }
Table of Contents
1NAME
2SYNOPSIS
3DESCRIPTION
3.1Reliability
3.2Terminology
3.3How it works.
4ATTRIBUTES
4.1max-workers
4.2max-jobs
4.3lo-threshold
,hi-threshold
4.4queued
4.5running
4.6completed
4.7empty
4.8quiet
5METHODS
5.1do-async( &code, |params --> Async::Workers::Job )
5.2shutdown
5.3workers
5.4workers( UInt $num )
5.5set-threshold( UInt :$lo, Num :$hi )
5.6on_msg( &callback )
5.7messages
6HELPER SUBS
6.1stop-worker($rc?, :$soft = False)
7PROCEDURAL
7.1async-workers( |params --> Async::Workers:D )
7.2do-async
7.3shutdown-workers
8AUTHOR
9LICENSE
NAME
Async::Workers
- Asynchronous threaded workersSYNOPSIS
use Async::Workers;my $wm = Async::Workers.new( :max-workers(5) );
for 1..10 -> $n {
$wm.do-async: {
sleep 1.rand;
say "Worker #$n";
}
}await $wm;
DESCRIPTION
This module provides an easy way to execute a number of jobs in parallel while allowing to keep the resources consumed by your code under control.
Both OO and procedural interfaces are provided.
Reliability
This module has been tested by running 20k repetitions of it's test suite using 56 parallel processes. This doesn't prove there're no bugs, but what can be told for certain is that within the tested scenarios the robustness is high enough.
Terminology
job is what gets executed. Depending on context, a job could be an instance of
Async::Workers::Job
class, or a user provided code object.worker is an instance of
Async::Workers::Worker
class. It is controlling a dedicated thread in which the job code is ran.worker manager or just manager is an instance of
Async::Workers
class which controls the execution flow and manages workers.How it works.
The goal is achieved by combining a queue of jobs and a number of pre-spawned threads controlled by workers. A job is picked from the queue by a currently unoccupied worker and the code object associated with it is invoked. Since the number of workers is limited it is easier to predict and plan CPU usage.
Yet, it is still possible to over-use memory and cause heavy swapping or even overflows in cases when there is too many jobs are produced and an average one takes longer to complete than it is needed to generate a new one. To provide some control over this situation one can define hi and lo thresholds on the queue size. When the queue contains as many jobs, as defined by the hi threshold,
do-async
method blocks upon receiving a new job request and unblocks only when the queue shortens down to its lo threshold.The worker manager doesn't start workers until the first job is sent to the queue. It is also possible to shutdown all workers if they're no longer needed.
Some internal events are reported with messages from
Async::Workers::Msg
. See theon_msg
method below.ATTRIBUTES
max-workers
Maximum number of workers. Defaults to
$*KERNEL.cpu-cores
.
max-jobs
Set the maximum number of jobs a worker should process before stopping and letting the manager to spawn a new one. The functionality is not activated if the attribute is left undefined.
lo-threshold
,hi-threshold
Low and high thresholds of the queue size.
queued
Current queue size. If the queue has been blocked due to reaching
hi-threshold
then jobs awaiting for unblock are not counted toward this value.
running
The number of currently occupied workers.
completed
A
Promise
which is kept when manager completes all jobs after transitioning into shutdown state. When this happens the job queue is closed and all workers are requested to stop. Submission of a new job withdo-async
at this point will re-vivify the queue and return the manager into working state.In case of an internal failure the promise will be broken with an exception.
empty
A
Promise
which is kept each time the queue gets emptied. Note that the initially empty queue is not reflected with this attribute. Only when the queue contained at least one element and then went down to zero length this promise is kept. In other words, it happens whenAsync::Workers::Msg::Queue::Empty
is emitted.Immediately after being kept the attribute gets replaced with a fresh
Promise
. So that the following example will finish only if the queue has been emptied twice:await $wm.empty;
await $wm.empty;
quiet
If set to True then no exceptions thrown by jobs are reported. In this case it is recommended to monitor messages for
Async::Workers::Msg::Job::Died
.METHODS
do-async( &code, |params --> Async::Workers::Job )
Takes a
&code
object and wraps it into a job object.params
are passed to&code
when it gets executed.This method blocks if
hi-threshold
is defined and the queue size has reached the limit.If no error happens then the method returns an
Async::Workers::Job
instance. Otherwise it may throw eitherX::Manager::Down
if the manager is inshutdown
orcompleted
status; or it may throwX::Manager::NoQueue
if somehow the job queue has not been initialized properly.
shutdown
Switches the manager into shutdown state and closes the job queue. Since the queue might still contain some incomplete jobs it is likely to take some time until the
completed
promise gets kept. Normally it'd be helpful toawait
for the manager:my $wm = Async::Workers.new(...);
...
$wm.shutdown;
await $wm;In this case the execution blocks until the job queue is emptied. Note that at this point
completed
might still not been fulfilled because workers are being shutting down in the meanwhile.
workers
Returns the number of started workers.
workers( UInt $num )
Sets the maximum number of workers (
max-workers
attribute). Can be used at any time without shutting down the manager:$wm = Async::Worker.new: :max-workers(20);
$wm.do-async: &job1 for ^$repetitions;
$wm.workers($wm.workers - 5);
$wm.do-async: &job2 for ^$repetitions;If user increases the number of workers then as many additional ones are started as necessary.
On the contrary, if the number of workers is reduced then as many of them are requested to stop as needed to meet user's demand. Note that this is done by injecting special jobs. It means that for a really long queue it may take quite a time before the extra workers receive the stop command. This behaviour may change in the future.
set-threshold( UInt :$lo, Num :$hi )
Dynamically sets high and low queue thresholds. The high might be set to
Inf
to define unlimited queue size. Note that this would translate into undefined value ofhi-threshold
attribute.
on_msg( &callback )
Submits a
Async::Workers::Msg
message object to user code passed in&callback
. Internally this method does tapping on a messageSupply
and returns a resultingTap
object.The following messages can currently be emitted by the manager (names are shortened to not include
Async::Workers::Msg::
prefix):
Shutdown
- when the manager is switched into shutdown state
Complete
- when manager completed all jobs and shut down all workers
Exception
- when an internal failure is intercepted; the related exception object is stored in attributeexception
Worker
- not emitted, a base class for otherWorker
messages. Defines attributeworker
which contains the worker object
Worker::Started
- when a new worker thread has started
Worker::Complete
- when a worker finishes
Worker::Died
- when a worker throws.exception
attribute will then contain the exception thrown. This message normally should not be seen as it signals about an internal error.
Queue
– not emitted, a base class for otherQueue
messages. Defines attributesize
which contains queue size at the moment when message was emitted.
Queue::Inc
- queue size inceased; i.e. a new job submitted. Note that if the queue has reached the hi threshold then a job passed todo-async
doesn't make it into the queue and thus no message is emitted until the queue is unblocked.
Queue::Dec
– a job has finished and the queue size is reduced
Queue::Full
- hi threshold is reached
Queue::Low
- queue size reduced down to lo threshold
Queue::Empty
– the queue was emtied
Job
– not emitted, a parent class of job-related messages. Definesjob
attribute which holds aAsync::Workers::Job
object.
Job::Enter
- emitted right before a worker is about to invoke a job
Job::Complete
– emitted right after a job finishes
Job::Died
– when a job throws.exception
attribute contains the exception object.
messages
This method produces a
Supply
which emits messages.HELPER SUBS
stop-worker($rc?, :$soft = False)
Bypasses to the current worker
stop
method.If called from within a job code it would cause the worker controlling the job to stop. If this would reduce the number of workers to less than
max-workers
then the manager will spawn as many new ones as needed:$wm.do-async: {
if $something-went-wrong {
stop-worker
}
}Note that the job would be stopped too, unless
:soft
parameter is used. In this case both the job and its worker will be allowed to complete. The worker will stop after the job is done.PROCEDURAL
Procedural interface hides a singleton object behind it. The following subs are exported by the module:
async-workers( |params --> Async::Workers:D )
Returns the singleton object. Creates it if necessary. If supplied with parameters they're passed to the constructor. If singleton is already created then the parameters are ignored.
do-async
Bypasses to the corresponding method on the singleton.
do-async {
say "My task";
}
shutdown-workers
Bypasses to
shutdown
on the singleton.AUTHOR
Vadim Belman <[email protected]>
LICENSE
Artistic License 2.0
See the LICENSE file in this distribution.