Running functions periodically using Twisted's LoopingCall
Twisted is pretty cool-- it is very powerful, but I haven't had the easiest time learning it. Here is a simple example that runs a couple functions periodically (at different rates) using LoopingCall
.
For more information, here are the Twisted docs for LoopingCall.
from datetime import datetime
from twisted.internet.task import LoopingCall
from twisted.internet import reactor
def hyper_task():
print "I like to run fast", datetime.now()
def tired_task():
print "I want to run slowly", datetime.now()
lc = LoopingCall(hyper_task)
lc.start(0.1)
lc2 = LoopingCall(tired_task)
lc2.start(0.5)
reactor.run()
Results:
I like to run fast 2008-10-14 15:51:02.449537 I want to run slowly 2008-10-14 15:51:02.449915 I like to run fast 2008-10-14 15:51:02.551972 I like to run fast 2008-10-14 15:51:02.652013 I like to run fast 2008-10-14 15:51:02.752006 I like to run fast 2008-10-14 15:51:02.852008 I like to run fast 2008-10-14 15:51:02.952487 I want to run slowly 2008-10-14 15:51:02.952681 I like to run fast 2008-10-14 15:51:03.052012 I like to run fast 2008-10-14 15:51:03.152012 I like to run fast 2008-10-14 15:51:03.252010 I like to run fast 2008-10-14 15:51:03.352009 I like to run fast 2008-10-14 15:51:03.452008 I want to run slowly 2008-10-14 15:51:03.452206 I like to run fast 2008-10-14 15:51:03.552009 I like to run fast 2008-10-14 15:51:03.652013
Using TimerService with twistd¶
To create a daemon with twistd that achieves the same effect, use TimerService. TimerService runs LoopingCall under the hood. It is meant to be used with the Twisted Application infrastructure. See also the documentation on TimerService.
timerservice_ex.py
from datetime import datetime
from twisted.application import service
from twisted.application.internet import TimerService
def tired_task():
print "I want to run slowly", datetime.now()
application = service.Application("myapp")
ts = TimerService(0.5, tired_task)
ts.setServiceParent(application)
Run it:
$ twistd -y timerservice_ex.py
Console output is stored in twistd.log:
2010-09-20 18:53:50-0700 [-] Log opened. 2010-09-20 18:53:50-0700 [-] using set_wakeup_fd 2010-09-20 18:53:50-0700 [-] twistd 10.1.0 (/home/saltycrane/.virtualenvs/default/bin/python 2.6.5) starting up. 2010-09-20 18:53:50-0700 [-] reactor class: twisted.internet.selectreactor.SelectReactor. 2010-09-20 18:53:50-0700 [-] I want to run slowly 2010-09-20 18:53:50.896477 2010-09-20 18:53:51-0700 [-] I want to run slowly 2010-09-20 18:53:51.397043 2010-09-20 18:53:51-0700 [-] I want to run slowly 2010-09-20 18:53:51.897087 2010-09-20 18:53:52-0700 [-] I want to run slowly 2010-09-20 18:53:52.397047 2010-09-20 18:53:52-0700 [-] I want to run slowly 2010-09-20 18:53:52.897068 2010-09-20 18:53:53-0700 [-] I want to run slowly 2010-09-20 18:53:53.397073 2010-09-20 18:53:53-0700 [-] I want to run slowly 2010-09-20 18:53:53.897032 2010-09-20 18:53:54-0700 [-] I want to run slowly 2010-09-20 18:53:54.397083
Related posts
- Twisted web POST example w/ JSON — posted 2010-08-25
- Quick notes on trying the Twisted websocket branch example — posted 2010-05-24
- Running a Twisted Perspective Broker example with twistd — posted 2008-10-27
- Twisted links — posted 2008-10-21
- Can't block for a Deferred in Twisted — posted 2008-10-20
Comments
What's your general impression of Twisted? I'm a fan of the deferred model, but somehow each time I pick up Twisted I leave it aside due to a combination of documentation (lack of), breadth (too much), and general unfamiliarity. I've yet to figure out if Twisted is worth the effort to learn, versus using more conventional models.
hey Parand! I like Twisted... I think it is very powerful. You are right-- the documentation is lacking and it is difficult to learn. Bruce Eckels, among others, have noted this as well. I don't have a huge amount of experience with the alternatives, but I think Twisted's fundamental functionality (i.e. Deferreds and the event loop) are pretty cool. I'd imagine there are areas where this design shines, and areas where an alternative is the right choice. I am looking forward to learning more Twisted though.
I am still figuring out how to use everything properly in Twisted. For example, in my current project, I just incorporated a beanstalkd message queue (thanks to your post!) with my existing Twisted setup. However, the design doesn't seem quite right-- beanstalkd seems to provide redundant functionality, but I'm not sure the proper way to implement this in pure Twisted. I tried searching for Twisted message queue but couldn't find much. I will continue to look into it and post any new findings.
Exactly, Twisted and messaging have overlapping functionality. I'm trying to figure out if using a message queue gives me the important 90% of the functionality of Twisted with an easier programming model, of if I should bite the bullet and figure out Twiested.
My stuff spends a lot of time waiting on I/O so I think Twisted can help me speed up these things.
Hi all, i'm a absolute beginner with Twisted anf asynchronous programming, but i look at your code and i do not want use LoopingCall object; also i looked at Stomp and Message Queue Architecture from the tutorial at "http://cometdaily.com/2008/10/10/scalable-real-time-web-architecture-part-2-a-live-graph-with-orbited-morbidq-and-jsio/". That tutorial showcases a data broadcast (Simple Real-Time Graph) where data is produced from a "data_producer.py" launched on the server and sent to the connected client towards stomp channels (using Twisted's LoopingCall object) every second, then in synchronous way.
There was the code (from "data_producer.py") that use also LoopingCall functions:
+-------------------------------------+
class DataProducer(StompClientFactory):
def recv_connected(self, msg):
print 'Connected; producing data'
self.data = [
int(random()*MAX_VALUE)
for
x in xrange(DATA_VECTOR_LENGTH)
]
self.timer = LoopingCall(self.send_data)
self.timer.start(INTERVAL/1000.0)
def send_data(self):
# modify our data elements
self.data = [
min(max(datum+(random()-.5)*DELTA_WEIGHT*MAX_VALUE,0),MAX_VALUE)
for
datum in self.data
]
self.send(CHANNEL_NAME, json.encode(self.data))
reactor.connectTCP('localhost', 61613, DataProducer())
reactor.run()
+-------------------------------------+
Now, i saw your examples, however i want to modify that code from the tutorial to realize monitoring session that broadcasts data generated from data_producer in asynchronous way, as soon as they were received from the outside world and immediately processed towards the stomp channels. I tried to modify "recv_message" and "send_data" defs and make it work, but with no success: data were generated and shown onto the stdout but not sent towards connected clients, with orbited, python stomper's or stompservices' example programs (stompbuffer-rx.py), etc.
Can you help me to undestand with simple examples how handling Twisted functions to implement these asynchronous capabilities without using LoopingCall object?
There is my simple code: . I looked at
+-------------------------------------+
class DataProducer(StompClientFactory):
def recv_connected(self, msg):
# Once connected, I want to subscribe to my the message queue
self.data = "Initialize..."
# What goes now at this point? <------------
??????????? # <---------------------------
def send_data(self):
try:
while 1:
# Read data (this is a string) from outside world
frame=RecData(smon)
# Show it towards stdout
WriteLog(frame)
#
self.data=frame
self.send("broadcast/monitor", json.encode(self.data))
except ...
reactor.connectTCP('localhost', 61613, DataProducer())
reactor.run()
+-------------------------------------+
Thanks for your appreciated help.
Alfredo
hello all: I used twisted and udp protocol,and set a LoopingCall which will run every minute to insert some data to mysql, but now I find the Loop only run for about 20 minutes and never run again! so what's wrong? Can someone help me ? Thanks!