On Fri, Oct 14, 2011 at 8:27 PM, Marc Lehmann <[email protected]> wrote: >> Here's how the problem manifests itself in gevent: >> time.sleep(7) # system call sleep >> gevent.sleep(10) # this uses ev_timer to wake up the coroutine. it >> sleeps for 3 seconds instead. > > Well, you can always call ev_now_update after such a long blocking > operation. Or take timestamps more often, to get better accuracy. Or use > proper timeouts.
I know about ev_now_update(). In fact, I've suggested to Shaun on gevent mailing list to call ev_now_update() periodically via setitimer. This only helps with timeouts bigger than the setitimer period though. Note, that inserting ev_now_update() manually is possible with gevent but is not a good suggestion in general, because it's hard to predict which operation is long and blocking. For example, GC can kick in at any moment. What does "take timestamps more often" means? What are proper timeouts? > Thats a pity - since there have been elaborate explanations given, what > exactly do you not understand? In the following scenario, 1) The computation takes place for 200ms. (We don't know that in advance, so simply inserting ev_now_update() call is not an option.) 2) A new non-blocking connect() is made. An I/O watcher is set up. 3) A timeout of 100ms is set up. what would be a good implementation of timeouts in 3) ? Apparently using ev_timer is naive and does not work. That's, in fact, what we do in gevent. How do we fix it? > (1) This can be fixed the good way - by a better design for example: your > timeout > relies on some other event _not_ occuring. if this is an I/O event, give it > higher priority. You can always add your own events by using an ev_check > watcher too. Giving the IO watcher higher priority than ev_timer's would not work here, would it? IIRC, priorities only matter within the same loop iteration, here the issue occurs when the timer has got an event but the IO hasn't yet. > (2) It can be fixed the lazy but correct way - if you don't whne *when* an > event occured, you have to ask the OS. If gettimefday (usually a fast > userspace function) is good enough for you, you can just call it when the > other event occurs and base your timeout on that. Can you elaborate on how to do that, provided it is applicable to the scenario above? > (3) And lastly, if you can't fix the design, and the lazy fix is too much > overhead, you can create a simple list and just start yxour timers in the > ev_prepare watcher. That seems like it would give us the kind of timers we need. I still wonder how (1) "the good way" or (2) "the correct way" can be applied to the example above. If it can not, then I wonder why don't we just start all timers in ev_prepare callback. >> Your Perl's Coro library probably has sleep() function that uses >> ev_timer as well? If that's the case, it's susceptible to this issue the >> same way. > > No, becauase Coro doesn't do I/O the same way, it uses design (2) from my > previous mails for actual I/O events. I was talking about sleep() without I/O (for simplicity). I installed Coro and it seems to do the same thing gevent does - it implements sleep() with bare ev_timer. Here's the gevent example ported to Perl/Coro: /home/denis$ cat corotest.pl use Coro::AnyEvent; Coro::AnyEvent::sleep 0.001; sleep 7; Coro::AnyEvent::sleep 10; /home/denis$ time perl corotest.pl real 0m10.025s user 0m0.016s sys 0m0.004s Sleep() is documented as "block the current thread for **at least** the given number of seconds". But it sleeps, like gevent.sleep(), for only 3 seconds instead of 10. In my opinion, Coro::AnyEvent::sleep is clearly broken according to its own documentation, would you agree with that? _______________________________________________ libev mailing list [email protected] http://lists.schmorp.de/cgi-bin/mailman/listinfo/libev
