Adjust the package revision; no actual code changes
[packages/trusty/python-eventlet.git] / eventlet / README.twisted
1 --work in progress--
2
3 Introduction
4 ------------
5 Twisted provides solid foundation for asynchronous programming in Python.
6 Eventlet makes asynchronous programming look like synchronous, thus
7 achieving higher signal-to-noise ratio than traditional twisted programs have.
8
9 Eventlet on top of twisted provides:
10  * stable twisted
11  * usable and readable synchronous style
12  * existing twisted code can be used without any changes
13  * existing blocking code can be used after trivial changes applied
14
15 NOTE: the maintainer of Eventlet's Twisted support no longer supports it; it still exists but may have had some breakage along the way.  Please treat it as experimental, and if you'd like to maintain it, please do!
16
17 Eventlet features:
18
19  * utilities for spawning and controlling greenlet execution:
20    api.spawn, api.kill, proc module
21  * utilities for communicating between greenlets:
22    event.Event, queue.Queue, semaphore.Semaphore
23  * standard Python modules that won't block the reactor:
24    eventlet.green package
25  * utilities specific to twisted hub:
26    eventlet.twistedutil package
27
28
29 Getting started with eventlet on twisted
30 ----------------------------------------
31
32 This section will only mention stuff that may be useful but it
33 won't explain in details how to use it. For that, refer to the
34 docstrings of the modules and the examples.
35
36 There are 2 ways of using twisted with eventlet, one that is
37 familiar to twisted developers and another that is familiar
38 to eventlet developers:
39
40  1. explicitly start the main loop in the main greenlet;
41  2. implicitly start the main loop in a dedicated greenlet.
42
43 To enable (1), add this line at the top of your program:
44 from eventlet.twistedutil import join_reactor
45 then start the reactor as you would do in a regular twisted application.
46
47 For (2) just make sure that you have reactor installed before using
48 any of eventlet functions. Otherwise a non-twisted hub will be selected
49 and twisted code won't work.
50
51 Most of examples/twisted_* use twisted style with the exception of
52 twisted_client.py and twisted_srvconnector.py. All of the non-twisted
53 examples in examples directory use eventlet-style (they work with any
54 of eventlet's hubs, not just twisted-based).
55
56 Eventlet implements "blocking" operations by switching to the main loop
57 greenlet, thus it's impossible to call a blocking function when you are
58 already in the main loop. Therefore one must be cautious in a twisted
59 callback, calling only a non-blocking subset of eventlet API here. The
60 following functions won't unschedule the current greenlet and are safe
61 to call from anywhere:
62
63 1. Greenlet creation functions: api.spawn, proc.spawn,
64    twistedutil.deferToGreenThread and others based on api.spawn.
65
66 2. send(), send_exception(), poll(), ready() methods of event.Event
67    and queue.Queue.
68
69 3. wait(timeout=0) is identical to poll(). Currently only Proc.wait
70    supports timeout parameter.
71
72 4. Proc.link/link_value/link_exception
73
74 Other classes that use these names should follow the convention.
75
76 For an example on how to take advantage of eventlet in a twisted
77 application using deferToGreenThread see examples/twisted_http_proxy.py
78
79 Although eventlet provides eventlet.green.socket module that implements
80 interface of the standard Python socket, there's also a way to use twisted's
81 network code in a synchronous fashion via GreenTransport class.
82 A GreenTransport interface is reminiscent of socket but it's not a drop-in
83 replacement. It combines features of TCPTransport and Protocol in a single
84 object:
85
86  * all of transport methods (like getPeer()) are available directly on
87    a GreenTransport instance; in addition, underlying transport object
88    is available via 'transport' attribute;
89  * write method is overriden: it may block if transport write buffer is full;
90  * read() and recv() methods are provided to retrieve the data from protocol
91    synchronously.
92
93 To make a GreenTransport instance use twistedutil.protocol.GreenClientCreator
94 (usage is similar to that of twisted.internet.protocol.ClientCreator)
95
96 For an example on how to get a connected GreenTransport instance,
97 see twisted_client.py, twisted_srvconnect.py or twisted_portforward.py.
98 For an example on how to use GreenTransport for incoming connections,
99 see twisted_server.py, twisted_portforward.py.
100
101
102 also
103 * twistedutil.block_on - wait for a deferred to fire
104   block_on(reactor.callInThread(func, args))
105 * twistedutil.protocol.basic.LineOnlyReceiverTransport - a green transport
106   variant built on top of LineOnlyReceiver protocol. Demonstrates how
107   to convert a protocol to a synchronous mode.
108
109
110 Coroutines
111 ----------
112
113 To understand how eventlet works, one has to understand how to use greenlet:
114 http://codespeak.net/py/dist/greenlet.html
115
116 Essential points
117
118 * There always exists MAIN greenlet
119 * Every greenlet except MAIN has a parent. MAIN therefore could be detected as g.parent is None
120 * When greenlet is finished it's return value is propagated to the parent (i.e. switch() call
121   in the parent greenlet returns it)
122 * When an exception leaves a greelen, it's propagated to the parent (i.e. switch() in the parent
123   re-raises it) unless it's a subclass of GreenletExit, which is returned as a value.
124 * parent can be reassigned (by simply setting 'parent' attribute). A cycle would be detected and
125   rejected with ValueError
126
127
128 Note, that there's no scheduler of any sort; if a coroutine wants to be
129 scheduled again it must take care of it itself. As an application developer,
130 however, you don't need to worry about it as that's what eventlet does behind
131 the scenes. The cost of that is that you should not use greenlet's switch() and
132 throw() methods, they will likely leave the current greenlet unscheduled
133 forever. Eventlet also takes advantage of greenlet's `parent' attribute,
134 so you should not meddle with it either.
135
136
137 How does eventlet work
138 ----------------------
139
140 Twisted's reactor and eventlet's hub are very similar in what they do.
141 Both continuously perform polling on the list of registered descriptors
142 and each time a specific event is fired, the associated callback function
143 is called. In addition, both maintain a list of scheduled calls.
144
145 Polling is performed by the main loop - a function that both reactor and hub have.
146 When twisted calls user's callback it's expected to return almost immediately,
147 without any blocking I/O calls.
148
149 Eventlet runs the main loop in a dedicated greenlet (MAIN_LOOP). It is the same
150 greenlet as MAIN if you use join_reactor. Otherwise it's a separate greenlet
151 started implicitly. The execution is organized in a such way that the switching
152 always involves MAIN_LOOP. All of functions in eventlet that appear "blocking"
153 use the following algorithm:
154
155 1. register a callback that switches back to the current greenlet when
156    an event of interest happens
157 2. switch to the MAIN_LOOP
158
159 For example, here's what eventlet's socket recv() does:
160
161 = blocking operation RECV on socket d =
162
163 user's greenlet (USER)             main loop's greenlet (MAIN_LOOP)
164       |
165 (inside d.recv() call)
166       |
167 add_descriptor(d, RECV)
168       |
169 data=MAIN_LOOP.switch() ---------> poll for events
170   ^---------------------\               |
171                         |              ... ---------------------------> may execute other greenlets here
172                         |               |
173                         |          event RECV on descriptor d?
174                         |               |
175                         |          d.remove_descriptor(d, RECV)
176                         |               |
177                         |          data = d.recv() # calling blocking op that will return immediately
178                         |               |
179                         \--------- USER.switch(data) # argument data here becomes return value in user's switch
180   return data
181