<div>Hi Arnar,</div>
<div> </div>
<div>Am I following io_operation right: the callback is an externally spawned (?) process which blocks waiting on the real IO operation but does not take up a slot in the Stackless round robin? And event.notify_when_ready_for_op returns instantly even if not ready? If so, then libevent seems to introduce a layer of multitasking that is not under the Stackless umbrella.</div>
<div> </div>
<div>The half-busy loop (with the time.sleep(0.0001)) is not necessary if the blocking select is used when no tasklets can run.</div>
<div> </div>
<div>The 1 ms and 2.5 ms were determined by experiment (you just loop on a usleep or nanosleep of some tiny positive amount - this always waits one tick, at least in C/Linux). This is obviously motherboard-dependent, and the newer motherboard had the slower response. I suspect interrupt response in general is getting sluggish, and they are afraid of a pileup of event code chained to the timer tick.</div>
<div> </div>
<div>Larry<br> </div>
<div><span class="gmail_quote">On 10/3/08, <b class="gmail_sendername">Arnar Birgisson</b> <<a href="mailto:arnarbi@gmail.com">arnarbi@gmail.com</a>> wrote:</span>
<blockquote class="gmail_quote" style="PADDING-LEFT: 1ex; MARGIN: 0px 0px 0px 0.8ex; BORDER-LEFT: #ccc 1px solid">Hi Larry,<br><br>On Fri, Oct 3, 2008 at 01:01, Larry Dickson <<a href="mailto:ldickson@cuttedge.com">ldickson@cuttedge.com</a>> wrote:<br>
> Wow! If that's your idea of a simple solution, I'd hate to see a complicated<br>> one ;-)<br><br>Well, if you look closely you'll see that it is basically a repeat of<br>the same pattern over and over:<br>
<br>def io_operation(*args,**kwargs):<br> def callback():<br> result = perform_real_io_operation(*args,**kwargs)<br> channel_dedicated_to_this_op.send(result)<br> event.notify_when_ready_for_op(callback)<br>
return channel_dedicated_to_this_op.receive()<br><br>This pattern is simply applied to file.read, file.write, socket.send,<br>socket.recv and socket.accept. The sleep function is even simpler.<br><br>As for the dispatching tasklet:<br>
<br>def _loop():<br> while _loop.running:<br> event.loop(True)<br> if stackless.getruncount() == 1:<br> time.sleep(0.0001)<br> stackless.schedule()<br>_loop.running = False<br><br>the time.sleep(0.0001) is simply an optimization in the case where<br>
there are no other tasklets runnable, in which case this would become<br>a busy loop eating 100% of cpu. You could leave it out and the<br>semantics would hold, in which case the loop is simply:<br><br>while running:<br> event.loop(True) # dispatch any ready IO events<br>
stackless.schedule() # run other tasklets<br><br>> Give me a week or so and I'll figure out how that works. What I do notice is<br>> the time.sleep(0.0001) [by the way, I believe the minimum sleep is actually<br>
> 1 ms in older PCs and 2.5 ms in newer PCs].<br><br>2.5 ms? That's ages.. do you have some references for this?<br><br>> Unless C/Linux select is<br>> designed horribly (and it could be), my second select approach gets an<br>
> instant response as soon as the hard interrupt handler returns control to<br>> the program. So my notion is not really reinventing the wheel - it is an<br>> improvement. And it seems to me it is an awful lot simpler. The only danger<br>
> - like any select - would be huge numbers of simultaneously waiting IOs.<br><br>Well, libevent uses the best available method on each platform, for<br>linux I believe it uses epoll and not select.<br><br>cheers,<br>Arnar<br>
</blockquote></div><br>