-
Notifications
You must be signed in to change notification settings - Fork 26
/
queue.perl
144 lines (117 loc) · 4.11 KB
/
queue.perl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#!/usr/bin/perl -w
# This is a simple job queue.
use strict;
use lib '../lib';
# sub POE::Kernel::TRACE_DEFAULT () { 1 }
# sub POE::Kernel::TRACE_GARBAGE () { 1 }
# sub POE::Kernel::ASSERT_DEFAULT () { 1 }
use POE;
### Configuration section.
# This is the maximum number of children permitted to be running at
# any moment.
my $child_max = 5;
### This is a "child" session. The "parent" session will ensure that
### $child_max of these are running at any given time.
# The parent session needs to create children from two places. Define
# a handy constructor rather than maintain duplicate copies of this
# POE::Session->create call.
sub create_a_child {
POE::Session->create
( inline_states =>
{ _start => \&child_start,
_stop => \&child_stop,
wake_up => \&child_awaken,
},
);
}
# The child session has started. Pretend to do something for a random
# amount of time.
sub child_start {
my ($kernel, $session, $parent, $heap) = @_[KERNEL, SESSION, SENDER, HEAP];
# Remember the parent.
$heap->{parent} = $parent;
# Take a random amount of time to "do" the "job".
my $delay = int rand 10;
warn "Child ", $session->ID, " will take $delay seconds to run.\n";
$kernel->delay( wake_up => $delay );
}
# The child has finished whatever it was supposed to do. Send the
# result of its labor back to the parent.
sub child_awaken {
my ($kernel, $session, $heap) = @_[KERNEL, SESSION, HEAP];
# Fabricate the hypothetical job's result.
my $result = int rand 100;
warn "Child ", $session->ID, " is done doing something. Result=$result\n";
# Post the result back to the parent. The child has nothing left to
# do, and so it stops.
$kernel->post($heap->{parent}, 'result', $session->ID, $result);
}
# The child has stopped. Display a message to help illustrate what's
# going on.
sub child_stop {
my $session = $_[SESSION];
warn "Child ", $session->ID, " is stopped.\n";
}
### This is the "parent" session. One of these will ensure that
### $child_max children are running beneath it. It's possible to have
### several parent sessions; each will manage a separate pool of
### children.
# The parent session is starting. Populate its pool with an initial
# group of child sessions.
sub parent_start {
$_[HEAP]->{child_count} = 0;
for (my $i=0; $i<$child_max; $i++) {
&create_a_child;
}
}
# The parent has either gained a new child or lost an existing one.
# If a new child is gained, track it. If an existing child is lost,
# then spawn a replacement.
sub parent_child {
my ($heap, $what, $child) = @_[HEAP, ARG0, ARG1];
# This child is arriving, either by being created or by being
# abandoned by some other session. Count it as a child in our pool.
if ($what eq 'create' or $what eq 'gain') {
$heap->{child_count}++;
warn( "Child ", $child->ID, " has appeared to parent ",
$_[SESSION]->ID, " (", $heap->{child_count},
" active children now).\n"
);
}
# This child is departing. Remove it from our pool count; if we
# have fewer children than $child_max, then spawn a new one to take
# the departing child's place.
elsif ($what eq 'lose') {
$heap->{child_count}--;
warn( "Child ", $child->ID, " has left parent ",
$_[SESSION]->ID, " (", $heap->{child_count},
" active children now).\n"
);
if ($heap->{child_count} < $child_max) {
&create_a_child;
}
}
}
# Receive a child session's result.
sub parent_result {
my ($child, $result) = @_[ARG0, ARG1];
warn "Parent received result from session $child: $result\n";
}
# Track when the parent leaves.
sub parent_stop {
warn "Parent ", $_[SESSION]->ID, " stopped.\n";
}
### Main loop. Start a parent session, which will, in turn, start its
### children. Run until everything is done; in this case, until the
### user presses Ctrl+C. Note: The children which are currently
### "working" will continue after Ctrl+C until they are "done".
POE::Session->create
( inline_states =>
{ _start => \&parent_start,
_stop => \&parent_stop,
_child => \&parent_child,
result => \&parent_result,
}
);
$poe_kernel->run();
exit;