… | |
… | |
212 | Similar to C<async>, but uses a coroutine pool, so you should not call |
212 | Similar to C<async>, but uses a coroutine pool, so you should not call |
213 | terminate or join on it (although you are allowed to), and you get a |
213 | terminate or join on it (although you are allowed to), and you get a |
214 | coroutine that might have executed other code already (which can be good |
214 | coroutine that might have executed other code already (which can be good |
215 | or bad :). |
215 | or bad :). |
216 | |
216 | |
217 | On the plus side, this function is faster than creating (and destroying) |
217 | On the plus side, this function is about twice as fast as creating (and |
218 | a completly new coroutine, so if you need a lot of generic coroutines in |
218 | destroying) a completely new coroutine, so if you need a lot of generic |
219 | quick successsion, use C<async_pool>, not C<async>. |
219 | coroutines in quick successsion, use C<async_pool>, not C<async>. |
220 | |
220 | |
221 | The code block is executed in an C<eval> context and a warning will be |
221 | The code block is executed in an C<eval> context and a warning will be |
222 | issued in case of an exception instead of terminating the program, as |
222 | issued in case of an exception instead of terminating the program, as |
223 | C<async> does. As the coroutine is being reused, stuff like C<on_destroy> |
223 | C<async> does. As the coroutine is being reused, stuff like C<on_destroy> |
224 | will not work in the expected way, unless you call terminate or cancel, |
224 | will not work in the expected way, unless you call terminate or cancel, |
… | |
… | |
247 | our $POOL_SIZE = 8; |
247 | our $POOL_SIZE = 8; |
248 | our $POOL_RSS = 16 * 1024; |
248 | our $POOL_RSS = 16 * 1024; |
249 | our @async_pool; |
249 | our @async_pool; |
250 | |
250 | |
251 | sub pool_handler { |
251 | sub pool_handler { |
252 | my $cb; |
|
|
253 | |
|
|
254 | while () { |
252 | while () { |
255 | eval { |
253 | eval { |
256 | while () { |
254 | &{&_pool_handler} while 1; |
257 | _pool_1 $cb; |
|
|
258 | &$cb; |
|
|
259 | _pool_2 $cb; |
|
|
260 | &schedule; |
|
|
261 | } |
|
|
262 | }; |
255 | }; |
263 | |
256 | |
264 | if ($@) { |
|
|
265 | last if $@ eq "\3async_pool terminate\2\n"; |
|
|
266 | warn $@; |
257 | warn $@ if $@; |
267 | } |
|
|
268 | } |
258 | } |
269 | } |
|
|
270 | |
|
|
271 | sub async_pool(&@) { |
|
|
272 | # this is also inlined into the unblock_scheduler |
|
|
273 | my $coro = (pop @async_pool) || new Coro \&pool_handler; |
|
|
274 | |
|
|
275 | $coro->{_invoke} = [@_]; |
|
|
276 | $coro->ready; |
|
|
277 | |
|
|
278 | $coro |
|
|
279 | } |
259 | } |
280 | |
260 | |
281 | =back |
261 | =back |
282 | |
262 | |
283 | =head2 STATIC METHODS |
263 | =head2 STATIC METHODS |
… | |
… | |
610 | # return immediately and can be reused) and because we cannot cede |
590 | # return immediately and can be reused) and because we cannot cede |
611 | # inside an event callback. |
591 | # inside an event callback. |
612 | our $unblock_scheduler = new Coro sub { |
592 | our $unblock_scheduler = new Coro sub { |
613 | while () { |
593 | while () { |
614 | while (my $cb = pop @unblock_queue) { |
594 | while (my $cb = pop @unblock_queue) { |
615 | # this is an inlined copy of async_pool |
595 | &async_pool (@$cb); |
616 | my $coro = (pop @async_pool) || new Coro \&pool_handler; |
|
|
617 | |
596 | |
618 | $coro->{_invoke} = $cb; |
|
|
619 | $coro->ready; |
|
|
620 | cede; # for short-lived callbacks, this reduces pressure on the coro pool |
597 | # for short-lived callbacks, this reduces pressure on the coro pool |
|
|
598 | # as the chance is very high that the async_poll coro will be back |
|
|
599 | # in the idle state when cede returns |
|
|
600 | cede; |
621 | } |
601 | } |
622 | schedule; # sleep well |
602 | schedule; # sleep well |
623 | } |
603 | } |
624 | }; |
604 | }; |
625 | $unblock_scheduler->{desc} = "[unblock_sub scheduler]"; |
605 | $unblock_scheduler->{desc} = "[unblock_sub scheduler]"; |