1 | =head1 NAME |
1 | =head1 NAME |
2 | |
2 | |
3 | AnyEvent::Impl::POE - AnyEvent adaptor for POE |
3 | AnyEvent::Impl::POE - AnyEvent adaptor for POE |
|
|
4 | |
|
|
5 | =encoding utf-8 |
4 | |
6 | |
5 | =head1 SYNOPSIS |
7 | =head1 SYNOPSIS |
6 | |
8 | |
7 | use AnyEvent; |
9 | use AnyEvent; |
8 | use POE; |
10 | use POE; |
… | |
… | |
39 | ->run >> at AnyEvent loading time and stop the kernel immediately |
41 | ->run >> at AnyEvent loading time and stop the kernel immediately |
40 | again. Unfortunately, due to another design bug in POE, this cannot be |
42 | again. Unfortunately, due to another design bug in POE, this cannot be |
41 | done (by documented means at least) without throwing away events in the |
43 | done (by documented means at least) without throwing away events in the |
42 | event queue. |
44 | event queue. |
43 | |
45 | |
|
|
46 | The author of POE verified that this is indeed true, and has no plans to |
|
|
47 | change this. |
|
|
48 | |
44 | This means that you will either have to live with lost events or you have |
49 | This means that you will either have to live with lost events or you have |
45 | to make sure to load AnyEvent early enough (this is usually not that |
50 | to make sure to load AnyEvent early enough (this is usually not that |
46 | difficult in a main program, but hard in a module). |
51 | difficult in a main program, but hard in a module). |
47 | |
52 | |
48 | =item One POE session per Event |
53 | =item One POE session per Event |
… | |
… | |
51 | immensely slow and makes watchers very large. The reason for this is |
56 | immensely slow and makes watchers very large. The reason for this is |
52 | lacking lifetime management (mostly undocumented, too). Without one |
57 | lacking lifetime management (mostly undocumented, too). Without one |
53 | session/watcher it is not possible to easily keep the kernel from running |
58 | session/watcher it is not possible to easily keep the kernel from running |
54 | endlessly. |
59 | endlessly. |
55 | |
60 | |
|
|
61 | This is not just a problem with the way AnyEvent has to interact with |
|
|
62 | POE, but is a principal issue with POEs lifetime management (namely |
|
|
63 | that stopping the kernel stops sessions, but AnyEvent has no control |
|
|
64 | over who and when the kernel starts or stops w.r.t. AnyEvent watcher |
|
|
65 | creation/destruction). |
|
|
66 | |
|
|
67 | From benchmark data it is not clear that session creation is that costly, |
|
|
68 | though - the real inefficiencies with POE seem to come from other sources, |
|
|
69 | such as event handling. |
|
|
70 | |
56 | =item One watcher per fd/event combo |
71 | =item One watcher per fd/event combo |
57 | |
72 | |
58 | POE, of course, suffers from the same bug as Tk and some other badly |
73 | POE, of course, suffers from the same bug as Tk and some other badly |
59 | designed event models in that it doesn't support multiple watchers per |
74 | designed event models in that it doesn't support multiple watchers per |
60 | fd/poll combo. The workaround is the same as with Tk: AnyEvent::Impl::POE |
75 | fd/poll combo. The workaround is the same as with Tk: AnyEvent::Impl::POE |
… | |
… | |
62 | certainly not nice to your resources. |
77 | certainly not nice to your resources. |
63 | |
78 | |
64 | Of course, without the workaround, POE also prints ugly messages again |
79 | Of course, without the workaround, POE also prints ugly messages again |
65 | that say the program *might* be buggy. |
80 | that say the program *might* be buggy. |
66 | |
81 | |
|
|
82 | While this is not good to performance, at least regarding speed, with a |
|
|
83 | modern Linux kernel, the overhead is actually quite small. |
|
|
84 | |
67 | =item Timing Deficiencies |
85 | =item Timing Deficiencies |
68 | |
86 | |
69 | POE manages to not have a function that returns the current time. This is |
87 | POE manages to not have a function that returns the current time. This is |
70 | extremely problematic, as POE can use different time functions, which can |
88 | extremely problematic, as POE can use different time functions, which can |
71 | differ by more than a second. In addition, most timer functions in POE |
89 | differ by more than a second - and user code is left guessing which one is |
72 | want an absoltue timestamp, which is hard to create if all you have is a |
90 | used. |
73 | relative time and no function to return the "current time". |
|
|
74 | |
91 | |
75 | AnyEvent works around this by using relative timer fucntions, in the hope |
92 | In addition, most timer functions in POE want an absoltue timestamp, which |
76 | that POE gets it right at least internally. |
93 | is hard to create if all you have is a relative time and no function to |
|
|
94 | return the "current time". |
|
|
95 | |
|
|
96 | And of course POE doesn't handle time jumps at all (not even when using |
|
|
97 | an event loop that happens to do that, such as L<EV>, as it does its own |
|
|
98 | unoptimised timer management). |
|
|
99 | |
|
|
100 | AnyEvent works around the unavailability of the current time using |
|
|
101 | relative timers exclusively, in the hope that POE gets it right at least |
|
|
102 | internally. |
77 | |
103 | |
78 | =item Event Non-Ordering |
104 | =item Event Non-Ordering |
79 | |
105 | |
80 | POE cannot guarentee the order of callback invocation for timers, and |
106 | POE cannot guarentee the order of callback invocation for timers, and |
81 | usually gets it wrong. That is, if you have two timers, one timing out |
107 | usually gets it wrong. That is, if you have two timers, one timing out |
82 | after another, the callbacks might be called in reverse order. |
108 | after another (all els ebeing equal), the callbacks might be called in |
|
|
109 | reverse order. |
83 | |
110 | |
84 | How one manages to even implement stuff that way escapes me. |
111 | How one manages to even implement stuff that way escapes me. |
85 | |
112 | |
86 | =item Child Watchers |
113 | =item Child Watchers |
87 | |
114 | |
88 | POE offers child watchers - which is a laudable thing, as few event loops |
115 | POE offers child watchers - which is a laudable thing, as few event loops |
89 | do. Unfortunately, they cannot even implement AnyEvent's simple child |
116 | do. Unfortunately, they cannot even implement AnyEvent's simple child |
90 | watchers: they are not generic enough. |
117 | watchers: they are not generic enough (even the POE implementation itself |
|
|
118 | isn't generic enough to let properly designed event loops such as EV use |
|
|
119 | their child watcher instead - it insist on doing it itself the slow way). |
91 | |
120 | |
92 | Of course, if POE reaps an unrelated child it will also output a message |
121 | Of course, if POE reaps an unrelated child it will also output a message |
|
|
122 | for it that you cannot suppress (which shouldn't be too surprising at this |
93 | for it. Very professional. |
123 | point). Very professional. |
94 | |
124 | |
95 | As a workaround, AnyEvent::Impl::POE will take advantage of undocumented |
125 | As a workaround, AnyEvent::Impl::POE will take advantage of undocumented |
96 | behaviour in POE::Kernel to catch the status fo all child processes. |
126 | behaviour in POE::Kernel to catch the status of all child processes. |
97 | |
127 | |
98 | Unfortunately, POE's child handling is racy: if the child exits before the |
128 | Unfortunately, POE's child handling is racy: if the child exits before the |
99 | handler is created (which is impossible to guarantee...), one has to wait |
129 | handler is created (which is impossible to avoid in general), one has to |
100 | for another event to occur, which can take an indefinite time (apparently |
130 | wait for another event to occur, which can take an indefinite amount of |
101 | POE does a busy-waiting loop every second, but this is not guarenteed |
131 | time (apparently POE does a busy-waiting loop every second, but this is |
102 | or documented, so in practise child status events can be delayed for a |
132 | not guarenteed or documented, so in practise child status events can be |
103 | second). |
133 | delayed for up to a second "only" at least in the current version). |
104 | |
134 | |
105 | How one manages to have such a glaring bug in an event loop after ten |
135 | How one manages to have such a glaring bug in an event loop after ten |
106 | years of development escapes me. |
136 | years of development escapes me. |
107 | |
137 | |
108 | =item Documentation Quality |
138 | =item Documentation Quality |
109 | |
139 | |
110 | At the time of this writing, POE was in its tenth year. Still, its |
140 | At the time of this writing, POE was in its tenth year. Still, its |
111 | documentation is extremely lacking, making it impossible to implement |
141 | documentation is extremely lacking, making it impossible to implement |
112 | stuff as trivial as AnyEvent watchers without havign to resort to |
142 | stuff as trivial as AnyEvent watchers without having to resort to |
113 | undocumented behaviour or features. |
143 | undocumented behaviour or features. |
114 | |
144 | |
115 | For example, the POE::Kernel manpage has nice occurances of the word TODO |
145 | For example, the POE::Kernel manpage has nine occurances of the word TODO |
116 | with an explanation of whats missing. Some other gems: |
146 | with an explanation of whats missing. In general, the POE manpages are |
|
|
147 | littered with comments like "section not yet written". |
|
|
148 | |
|
|
149 | Some other gems: |
117 | |
150 | |
118 | This allows many object methods to also be package methods. |
151 | This allows many object methods to also be package methods. |
119 | |
152 | |
120 | This is nice, but since it doesn't document I<which> methods these are, |
153 | This is nice, but since it doesn't document I<which> methods these are, |
121 | this is utterly useless information. |
154 | this is utterly useless information. |
122 | |
155 | |
123 | Terminal signals will kill sessions if they are not handled by a |
156 | Terminal signals will kill sessions if they are not handled by a |
124 | "sig_handled"() call. The OS signals that usually kill or dump a |
157 | "sig_handled"() call. The OS signals that usually kill or dump a |
125 | process are con‐ sidered terminal in POE, but they never trigger a |
158 | process are considered terminal in POE, but they never trigger a |
126 | coredump. These are: HUP, INT, QUIT and TERM. |
159 | coredump. These are: HUP, INT, QUIT and TERM. |
127 | |
160 | |
128 | Although AnyEvent calls sig_handled, removing it has no apparent effects |
161 | Although AnyEvent calls C<sig_handled>, removing it has no apparent |
129 | on POE handling SIGINT. |
162 | effects on POE handling SIGINT. |
|
|
163 | |
|
|
164 | refcount_increment SESSION_ID, COUNTER_NAME |
|
|
165 | |
|
|
166 | Nowhere is explained which COUNTER_NAMEs are valid and which aren't - not |
|
|
167 | all scalars (or even strings) are valid counter names. Take your guess, |
|
|
168 | failure is of course completely silent. I found this out the hard way, as |
|
|
169 | the first name I came up with was silently ignored. |
|
|
170 | |
|
|
171 | get_next_event_time() returns the time the next event is due, in a form |
|
|
172 | compatible with the UNIX time() function. |
|
|
173 | |
|
|
174 | And surely, one would hope that POE supports subsecond accuracy as |
|
|
175 | documented elsewhere, unlike the explanation above implies. Yet: |
|
|
176 | |
|
|
177 | POE::Kernel timers support subsecond accuracy, but don’t expect too |
|
|
178 | much here. Perl is not the right language for realtime programming. |
|
|
179 | |
|
|
180 | ... of course, Perl is not the right language to expect subsecond accuray |
|
|
181 | - the manpage author must hate Perl to spread so much FUD in so little |
|
|
182 | space. The Deliantra game server logs with 100µs-accuracy because Perl is |
|
|
183 | fast enough to require this, and is still able to deliver map updates with |
|
|
184 | little jitter at exactly the right time. It does not, however, use POE. |
130 | |
185 | |
131 | Furthermore, since the Kernel keeps track of everything sessions do, it |
186 | Furthermore, since the Kernel keeps track of everything sessions do, it |
132 | knows when a session has run out of tasks to perform. |
187 | knows when a session has run out of tasks to perform. |
133 | |
188 | |
134 | This is impossible - how does the kernel now that a session is no longer |
189 | This is impossible - how does the kernel know that a session is no longer |
135 | watching for some (external) event (e.g. by some other session)? It |
190 | watching for some (external) event (e.g. by some other session)? It |
136 | cannot, and therefore this is wrong. |
191 | cannot, and therefore this is wrong - but you would be hard pressed to |
|
|
192 | find out how to work around this and tell the kernel manually about such |
|
|
193 | events. |
137 | |
194 | |
138 | It gets worse, though - the notion of "task" or "resource", although used |
195 | It gets worse, though - the notion of "task" or "resource", although used |
139 | throughout the documentation, is not defined in a usable way. For example, |
196 | throughout the documentation, is not defined in a usable way. For example, |
140 | waiting for a timeout is considered to be a task, waiting for a signal is |
197 | waiting for a timeout is considered to be a task, waiting for a signal is |
|
|
198 | not (a session that only waits for a signal is considered finished and |
141 | not. The user is left guessing when waiting for an event counts as task |
199 | gets removed). The user is left guessing when waiting for an event counts |
142 | and when not. |
200 | as task and when not (in fact, the issue with signals is mentioned in |
|
|
201 | passing in a section about child watchers and directly contradicts earlier |
|
|
202 | parts in that document). |
143 | |
203 | |
144 | One could go on endlessly - ten years, no usable docs. |
204 | One could go on endlessly - ten years, no usable documentation. |
145 | |
205 | |
146 | It is likely that differences between documentation, or the one or two |
206 | It is likely that differences between documentation, or the one or two |
147 | things I had to guess, cause unanticipated problems with the backend. |
207 | things I had to guess, cause unanticipated problems with this adaptor. |
148 | |
208 | |
149 | =item Bad API |
209 | =item Fragile and inconsistent API |
150 | |
210 | |
151 | The POE API is extremely inconsistent - sometimes you have to pass a |
211 | The POE API is extremely inconsistent - sometimes you have to pass a |
152 | session argument, sometimes it gets ignored, sometimes a session-specific |
212 | session argument, sometimes it gets ignored, sometimes a session-specific |
153 | method must not use a session argument. |
213 | method must not use a session argument. |
154 | |
214 | |
|
|
215 | Error handling is sub-standard as well: even for programming mistakes, |
|
|
216 | POE does not C<croak> but, in most cases, just sets C<$!> or simply does |
|
|
217 | nothing at all, leading to fragile programs. |
|
|
218 | |
155 | Sometimes registering a handler uses "eventname, parameter" (timeouts), |
219 | Sometimes registering a handler uses the "eventname, parameter" ordering |
156 | sometimes it is "parameter, eventname" (signals). There is little |
220 | (timeouts), sometimes it is "parameter, eventname" (signals). There is |
157 | consistency. |
221 | little consistency overall. |
|
|
222 | |
|
|
223 | =item Lack of knowledge |
|
|
224 | |
|
|
225 | The IO::Poll event loop provides an alternative that theoretically |
|
|
226 | scales better than select(). |
|
|
227 | |
|
|
228 | The IO::Poll "event loop" (who in his right mind would call that an event |
|
|
229 | loop) of course scales about identically (sometimes it is a bit faster, |
|
|
230 | sometimes a bit slower) to select in theory, and also in practise, of |
|
|
231 | course, as both are O(n) in the number of file descriptors, which is |
|
|
232 | rather bad. |
|
|
233 | |
|
|
234 | This is just one place where it gets obvious how little the author of the |
|
|
235 | POE manpage understands. |
158 | |
236 | |
159 | =back |
237 | =back |
160 | |
238 | |
161 | On the good side, AnyEvent allows you to write your modules in a 99% |
239 | On the good side, AnyEvent allows you to write your modules in a 100% |
162 | POE-compatible way (conflicting child watchers), without forcing your |
240 | POE-compatible way (bug-for-bug compatible even), without forcing your |
163 | module to use POE - it is still open to better event models, of which |
241 | module to use POE - it is still open to better event models, of which |
164 | there are plenty. |
242 | there are plenty. |
165 | |
243 | |
166 | =cut |
244 | =cut |
167 | |
245 | |
… | |
… | |
206 | } |
284 | } |
207 | |
285 | |
208 | sub timer { |
286 | sub timer { |
209 | my ($class, %arg) = @_; |
287 | my ($class, %arg) = @_; |
210 | my $after = delete $arg{after}; |
288 | my $after = delete $arg{after}; |
211 | my $cb = delete $arg{cb}; |
289 | my $cb = delete $arg{cb}; |
212 | my $session = POE::Session->create ( |
290 | my $session = POE::Session->create ( |
213 | inline_states => { |
291 | inline_states => { |
214 | _start => sub { |
292 | _start => sub { |
215 | $_[KERNEL]->delay_set (timeout => $after); |
293 | $_[KERNEL]->delay_set (timeout => $after); |
216 | }, |
294 | }, |