473,796 Members | 2,654 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

how do you implement a reactor without a select?

I have always been curious about how people implement mainloops (or,
in Twisted terminology, reactors). So I sit down and I wrote the
following simple implementation:

import itertools

class SimpleReactor(o bject):

DELAY = 0.001 # seconds

def __init__(self):
self._event = {} # action id -(scheduled time, action, args)
self._counter = itertools.count (1) # action id generator
self.running = False

def callLater(self, deltat, action, *args):
"""Schedule an action with arguments args in deltat seconds.
Return the action id"""
now = time.time()
i = self._counter.n ext()
self._event[i] = now + deltat, action, args
return i

def cancelCallLater (self, action_id):
"Cancel the action identified by action_id"
del self._event[action_id]

def default_action( self): # to be overridden
"Invoked at each lap in the mainloop"
time.sleep(self .DELAY) # don't run too fast, rest a bit

def cleanup_action( self): # to be overridden
"Invoked at the end of the mainloop"

def manage_exc(self , e):
"Invoked at each call"
raise e

def dooneevent(self ):
"Perfom scheduled actions"
now = time.time()
for i, (start_time, action, args) in self._event.ite ms():
if now >= start_time: # it's time to start the action
self.cancelCall Later(i) # don't run it again
try:
action(*args)
except Exception, e:
self.manage_exc (e)

def run(self):
"Run the main loop"
self.running = True
try:
while self.running:
self.default_ac tion()
self.dooneevent ()
except KeyboardInterru pt:
print 'Stopped via CTRL-C'
finally:
self.cleanup_ac tion()

def stop(self):
self.running = False

Notice that I copied the Twisted terminology, but
I did not look at Twisted implementation because I did not want to
use a select (I assume that the GUI mainloops do not use it either).
The trick I use is to store the actions to perform (which are
callables identified by an integer) in an event dictionary and
to run them in the mainlooop if the current time is greater than
the scheduled time.
I had to add a time.sleep(.001 ) call in the default_action to avoid
consuming 100%
of the CPU in the loop.
I wonder if real mainloops are done in this way and how bad/good is
this implementation compared to a serious one. Any suggestion/hint/
advice
is well appreciated. Thanks,

Michele Simionato

May 7 '07 #1
10 1960
Notice that I copied the Twisted terminology, but
I did not look at Twisted implementation because I did not want to
use a select (I assume that the GUI mainloops do not use it either).
Why do you assume that? It's a wrong assumption. Yielding a thread/process
until the OS wakes it up because of IO to be performed is the proper way to
go. And at least in unix, IO is _everything_, also mouse-movements and
keyboard events. Most probably the OS will have specialized APIs (or some
wrapper lib has) that allow for reactor registration for events of
different kinds including timers. But basically, it's select - I mean you
could easily offer a timer as a file-object as well. Not sure if that's
done though.
The trick I use is to store the actions to perform (which are
callables identified by an integer) in an event dictionary and
to run them in the mainlooop if the current time is greater than
the scheduled time.
I had to add a time.sleep(.001 ) call in the default_action to avoid
consuming 100%
of the CPU in the loop.
I wonder if real mainloops are done in this way and how bad/good is
this implementation compared to a serious one. Any suggestion/hint/
advice
is well appreciated. Thanks,
It's ok, but of course more wasteful than it needs to be - better would be
full delegation to the OS.

Diez
May 7 '07 #2
Michele Simionato <mi************ ***@gmail.comwr ote:
I wonder if real mainloops are done in this way and how bad/good is
this implementation compared to a serious one. Any suggestion/hint/
advice is well appreciated. Thanks,
Module sched in Python's standard library may suggest one clearly-better
approach: when you know in advance when future events are scheduled for,
sleep accordingly (rather than polling every millisecond). sched's
sources are simple enough to study, and its architecture clean and
strong enough that it's easy to extend to other cases, e.g. where
previously-unscheduled events may be delivered from other threads,
without necessarily hacking the sources.

Specifically, sched implements the Dependency Injection DP: rather than
just calling time.time and time.sleep, it accepts those two callables
upon initialization. This makes it easy, among many other
customizations, to pass instead of time.sleep a user-coded callable
(typically a bound method) that "sleeps" by a wait-with-timeout on a
Queue (so that other threads, by putting an event on the Queue in
question, immediately wake up the scheduler, etc, etc).
Alex
May 7 '07 #3
On May 7, 4:39 pm, a...@mac.com (Alex Martelli) wrote:
Michele Simionato <michele.simion ...@gmail.comwr ote:
I wonder if real mainloops are done in this way and how bad/good is
this implementation compared to a serious one. Any suggestion/hint/
advice is well appreciated. Thanks,

Module sched in Python's standard library may suggest one clearly-better
approach: when you know in advance when future events are scheduled for,
sleep accordingly (rather than polling every millisecond). sched's
sources are simple enough to study, and its architecture clean and
strong enough that it's easy to extend to other cases, e.g. where
previously-unscheduled events may be delivered from other threads,
without necessarily hacking the sources.

Specifically, sched implements the Dependency Injection DP: rather than
just calling time.time and time.sleep, it accepts those two callables
upon initialization. This makes it easy, among many other
customizations, to pass instead of time.sleep a user-coded callable
(typically a bound method) that "sleeps" by a wait-with-timeout on a
Queue (so that other threads, by putting an event on the Queue in
question, immediately wake up the scheduler, etc, etc).

Alex
I know about sched (it was the first thing I looked at): the problem
is that sched
adopt a blocking approach and it basically requires threads, whereas I
wanted to
avoid them. Diez B. Roggisch's reply is closer to my expectations:
>Most probably the OS will have specialized APIs (or some
wrapper lib has) that allow for reactor registration for events of different
kinds including timers.
But what kind of specialized API do I have at my disposition for
timers on Linux?
It looks like this is the question I should have asked the first
time ;)
Michele Simionato

May 7 '07 #4
Michele Simionato wrote:
Notice that I copied the Twisted terminology, but
I did not look at Twisted implementation because I did not want to
use a select (I assume that the GUI mainloops do not use it either).
The trick I use is to store the actions to perform (which are
callables identified by an integer) in an event dictionary and
to run them in the mainlooop if the current time is greater than
the scheduled time.
I had to add a time.sleep(.001 ) call in the default_action to avoid
consuming 100%
of the CPU in the loop.
Busy-looping like that is ugly and inefficient, even with the sleep
thrown in.

Most GUI main loops _do_ use either select() or poll(). When Xt/GTK/
Qt/etc have function like "gtk_add_in put" which takes an fd that
you'll get notified about if it's written to while you're in the main
loop, that's just adding another fd to the select() loop.

There are other ways to wait for events on an fd, but they tend to be
less portable. Depending on your Unix flavor, epoll, /dev/poll,
kqueues, kevent, queued realtime signals, or something else might be
available from the OS (but probably not from Python without futzing
with ctypes or writing an extension). If you want details, check out
http://www.kegel.com/c10k.html

The alternatives usually aren't really faster unless you have hundreds
of connections, though--select/poll have major portability advantages,
so go with them unless you have a compelling reason.

May 7 '07 #5
Michele Simionato <mi************ ***@gmail.comwr ote:
...
I know about sched (it was the first thing I looked at): the problem
is that sched
adopt a blocking approach and it basically requires threads, whereas I
As the "sleep for time N" callable, you can pass any callable you wish;
I suggested one based on Queue.wait with timeout, which would indeed
require some other thread to wake it, but any kind of system call which
allows timeouts, such as select or poll, would work just as well.
wanted to
avoid them. Diez B. Roggisch's reply is closer to my expectations:
Most probably the OS will have specialized APIs (or some wrapper lib
has) that allow for reactor registration for events of different kinds
including timers.

But what kind of specialized API do I have at my disposition for
timers on Linux?
It looks like this is the question I should have asked the first
time ;)
What do you expect from "timers on Linux" that you could not get with a
simple "sleep for the next N milliseconds"? A timer (on Linux or
elsewhere) can jog your process N milliseconds from now, e.g. with a
SIGALRM or SIGPROF, and you can set one with the setitimer syscall
(presumably accessible via ctypes, worst case -- I've never used it from
Python, yet), but how would that help you (compared to plain sleep,
select, poll, or whatever else best fits your need)?
Alex
May 8 '07 #6
On May 8, 4:53 am, a...@mac.com (Alex Martelli) wrote:
What do you expect from "timers on Linux" that you could not get with a
simple "sleep for the next N milliseconds"? A timer (on Linux or
elsewhere) can jog your process N milliseconds from now, e.g. with a
SIGALRM or SIGPROF, and you can set one with the setitimer syscall
(presumably accessible via ctypes, worst case -- I've never used it from
Python, yet), but how would that help you (compared to plain sleep,
select, poll, or whatever else best fits your need)?
I hoped there was a library such thay I could register a Python
callable (say
a thunk) and having it called by the linux timer at time t without
blocking
my process. But if a Linux timer will just send to my process an
alarm, I would need to code myself a mechanism waiting for the alarm
and doing the function call. In that case as you say, I would be
better off with a select+timeout or a even with a queue+timeout, which
already do most of the job.

Michele Simionato

May 8 '07 #7
On May 7, 7:36 pm, "sjdevn...@yaho o.com" <sjdevn...@yaho o.comwrote:
>
Busy-looping like that is ugly and inefficient, even with the sleep
thrown in.

Most GUI main loops _do_ use either select() or poll(). When Xt/GTK/
Qt/etc have function like "gtk_add_in put" which takes an fd that
you'll get notified about if it's written to while you're in the main
loop, that's just adding another fd to the select() loop.

There are other ways to wait for events on an fd, but they tend to be
less portable. Depending on your Unix flavor, epoll, /dev/poll,
kqueues, kevent, queued realtime signals, or something else might be
available from the OS (but probably not from Python without futzing
with ctypes or writing an extension). If you want details, check outhttp://www.kegel.com/c10k.html

The alternatives usually aren't really faster unless you have hundreds
of connections, though--select/poll have major portability advantages,
so go with them unless you have a compelling reason.
I see where you are coming from. In a GUI or in a Web server most
of the time is spent waiting from input, so a busy loop design would
be a terrible
design indeed. But I had another use case in mind. The code I posted
is
extracted from a batch script I have, called 'dbexplorer'. The script
performs lots of
queries in a database and find out "bad" data according to some
criterium.
So at each iteration there is a default action which is nontrivial; it
becomes
a time.sleep only at the end, when the batch has finished its job and
it
is waiting for input.In normal conditions most of the time is spent
doing
something, not waiting, so the busy loop design here is not so bad.
Still I wanted to know what my alternatives were. And from this thread
I gather the impression that actually the only portable alternative is
using some
kind of select, unless I want to use threads, and in that case the
scheduler approach could be viable.
Anyway, that C10K page is really an interesting resource, thanks for
pointing it out!

Michele Simionato

May 8 '07 #8
Michele Simionato <mi************ ***@gmail.comwr ote:
On May 8, 4:53 am, a...@mac.com (Alex Martelli) wrote:
What do you expect from "timers on Linux" that you could not get with a
simple "sleep for the next N milliseconds"? A timer (on Linux or
elsewhere) can jog your process N milliseconds from now, e.g. with a
SIGALRM or SIGPROF, and you can set one with the setitimer syscall
(presumably accessible via ctypes, worst case -- I've never used it from
Python, yet), but how would that help you (compared to plain sleep,
select, poll, or whatever else best fits your need)?

I hoped there was a library such thay I could register a Python
callable (say
a thunk) and having it called by the linux timer at time t without
blocking
my process. But if a Linux timer will just send to my process an
alarm, I would need to code myself a mechanism waiting for the alarm
and doing the function call. In that case as you say, I would be
better off with a select+timeout or a even with a queue+timeout, which
already do most of the job.
Python or not, I don't know of a way to "register a callback" from the
OS without using threads. Considering that your callback WOULD be
executing on a different thread no matter what (your "only" thread being
blocked on some blocking syscall, or executing other code -- having
other code in your process suddenly start executing at that point is
pre-emptive threading, by whatever name you choose to call it), it's not
clear to me why the "avoiding threads" issue should matter to you.
Alex
May 8 '07 #9
On 2007-05-08, Michele Simionato <mi************ ***@gmail.comwr ote:
On May 8, 4:53 am, a...@mac.com (Alex Martelli) wrote:
>What do you expect from "timers on Linux" that you could not get with a
simple "sleep for the next N milliseconds"? A timer (on Linux or
elsewhere) can jog your process N milliseconds from now, e.g. with a
SIGALRM or SIGPROF, and you can set one with the setitimer syscall
(presumably accessible via ctypes, worst case -- I've never used it from
Python, yet), but how would that help you (compared to plain sleep,
select, poll, or whatever else best fits your need)?

I hoped there was a library such thay I could register a Python
callable (say
a thunk) and having it called by the linux timer at time t without
blocking
I once played with the following module to do something similar.
Maybe it is usefull to you as is, or can give you an idea on how
to proceed. I only tested it on linux.

---------------------------- alarm.py --------------------
m signal import signal, SIG_IGN, SIGALRM
from time import time
from thread import allocate_lock
from heapq import heappush, heappop
from os import kill, getpid
import errno

from select import select, error as SelectException

from ctypes import *
libc = cdll.LoadLibrar y("/lib/libc.so.6")

class _timeval(Struct ure):
_fields_ = [("tv_sec" , c_long), ("tv_usec", c_long)]

def timeval(tm):
sec = int(tm)
usec = int(1000000 * (tm - sec))
return _timeval(sec, usec)

class itimerval(Struc ture):
_fields_ = [("it_interva l", _timeval), ("it_value", _timeval)]
def alarm(tm):
tv = timeval(tm)
ti = timeval(0.0)
ntv = itimerval(ti, tv)
otv = itimerval(timev al(0.0), timeval(0.0))
rt = libc.setitimer( 0, byref(ntv), byref(otv))
#print otv.it_value.tv _sec , otv.it_value.tv _usec
if rt:
raise ValueError
else:
return otv.it_value.tv _sec + otv.it_value.tv _usec / 1000000.0

def sleep(tm):
wakeup = time() + tm
while tm >= 0:
try:
select([],[],[],tm)
except SelectException , Err_Info:
#print dir(Err_Info)
if Err_Info[0] != errno.EINTR:
raise
tm = wakeup - time()

alarms = []
alarm_lock = allocate_lock()

def AlarmHandler(sg nr, frame):
alarm_lock.acqu ire()
now = time()
while alarms and alarms[0].moment <= now:
current = heappop(alarms)
if not current.cancele d:
current.func(*c urrent.args, **current.kwds)
current.execute d = True
now = time()
alarm_lock.rele ase()
if alarms:
#print alarms[0].moment - now, alarms
alarm(alarms[0].moment - now)

signal(SIGALRM, AlarmHandler)

class Alarm(object):
def __init__(self, tp, func, *args, **kwds):
alarm(0)
try:
alarm_lock.acqu ire()
self.canceled = False
self.executed = False
self.func = func
self.args = args
self.kwds = kwds
self.moment = tp
heappush(alarms , self)
now = time()
delta = alarms[0].moment - now
#print alarms
finally:
alarm_lock.rele ase()
if delta <= 0:
pass
kill(getpid(), SIGALRM)
else:
alarm(delta)

def __cmp__(self, other):
return cmp(self.moment , other.moment)

def __str__(self):
return "<Alarm for %d>" % self.moment

__repr__ = __str__

def Cancel(self):
try:
alarm_lock.acqu ire()
if self.executed:
raise ValueError, "Cancelatio n was too late"
else:
self.canceled = True
except:
alarm_lock.rele ase()

-----------------------------------------------------------------------------------------------

You use it as follows:

from alarm import Alarm

alert = Alarm(exucutemo ment, function, positionalargum ents, keywordargument s)

# unless alert.Cancel is called before the alert went off, the function
# with its arguments will be called at the specified time.

# If you are using threads, you are advised to do most of the work in a
# different thread and leave the main thread to only treat the alarms.
May 8 '07 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

0
1006
by: Andy Leszczynski | last post by:
Python 2.3, one of the latest Twisted version: I noted that under Linux there is not way to Control-C the reactor loop. After digging a little I found that following change helpes: # diff base.py{,.ori} > 302d301 < print "1",sysEvtTriggers 305d303
4
8438
by: Matt | last post by:
In ASP page, there is a "SELECT ALL" button, when user click it, it will select all checkboxes. I am not sure should I use client-side code to do that? the following is my approach but it didnt work. <script language="JavaScript"> function selectAllCheckBox() { //alert(document.addzone.c1.value); document.addzone.c1.value = "on"; } </script>
1
6170
by: javaq | last post by:
I am using Oracle9iR2 / JDBC. I need to implement a search facility similar to google.com on the database I have. There are 20 tables in the database and around 30000 records in total. I have to search only in VARCHAR2 and CLOB fields. Each table has an ID (PK) column. How to write a single query that search these tables for given string. Here is a sample for quick understanding... ............................................ CREATE...
11
1569
by: Gent | last post by:
I have a table named Holding_Value that has several fields in it among which are UID, fkHolding, EffDate, Units, MarketValue, AssetPrice. UID is an identity field and fkHolding is a foreign key to a different table. EffDate is the the effective date while units and marketvalue are values stored in the table. what i'm trying to do is get all the values (fkHolding, Effdate, Units, MarketValue) for all fkHolding for a specific date. That...
2
2719
by: Paul Aspinall | last post by:
Hi Has anyone any experiences of using .NET Reactor, in order to protect their assemblies?? http://www.eziriz.com/ Any opinions / experiences appreciated. Thanks
1
1472
by: Divvy Bollocks | last post by:
// A big 7 and three-quarters size "Hello" to all C++ programmers out there. This here is the second program what I've // ever wrote, the first being a "Fuck off world you cunt" program. It's a nice little poker patience program, poker // patience being a patience game whereby 10 poker hands are placed on the table in a 5x5 square. Try it if you like. // It's not really a C++ program as such, more of a SLOGic program heh heh. It writes...
1
4309
by: maxime_phan | last post by:
hello, everyone I use twisted 1.3 in my python application. in my program, I have one server and on client running at same time (so 2 reactor.run(installSignalHandlers=0) ) the client run in one thread and the server in an other thread ( reactor.callInThread(self.client... , reactor.callInThread(self.server .....) when I catch "escape" button, I make a reactor.stop() but it doesn't seem to work and quit, and the application freeze. does...
19
40819
by: UG | last post by:
I just wanted to know whether any timer facility exists in C, as it is not mentioned in K&R 2, or in the ISO Draft. By timer function i mean that when we use standard input function like scanf() or getch() or any other function, the interface stops to take input from user but what if user doesn't give input for hours, the program will still be waiting. Is there any way to circumvent the scanf() (or any other input function for that matter)...
11
2672
by: Toast | last post by:
First of all... I'm very new to all of this and really do not know anything more than how to "snoop" and try to see what things might be causing problems. I do not know how to program. Everything here is not in a verbatim or verbose format. I think I did well enough though, considering I don't even know how to explain these things. All specs are at end of this post. Ok... the issue I have smtp set up properly for outgoing "fake" and I...
0
9679
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
10453
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
10223
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
10172
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
1
7546
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
6785
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
5441
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
2
3730
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
2924
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.