File: threads.rst

package info (click to toggle)
kaa-base 0.6.0%2Bsvn4596-1
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd, stretch, wheezy
  • size: 2,348 kB
  • ctags: 3,068
  • sloc: python: 11,094; ansic: 1,862; makefile: 74
file content (205 lines) | stat: -rw-r--r-- 6,236 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
.. _threads:

Thread Support
==============

.. _threaded:

The threaded decorator
----------------------

Any function or method may be decorated with ``@kaa.threaded()`` which takes
two optional arguments: a thread name, and a priority. If a thread name is
specified, the decorated function is wrapped in
:class:`~kaa.ThreadPoolCallable`, and invocations of that function are queued
to be executed across one or more threads. If the thread name is ``kaa.MAINTHREAD`` the
decorated function is invoked from the main thread. If no thread name is
specified, the function is wrapped in :class:`~kaa.ThreadCallable` so that each
invocation is executed in a separate thread. Because these callables return
:class:`~kaa.ThreadInProgress` objects, which are derived from
:class:`~kaa.InProgress`, they may be yielded from :ref:`coroutines <coroutines>`.

For example::

  @kaa.threaded()
  def do_blocking_task():
     [...]
     return 42

  @kaa.coroutine()
  def do_something_else():
     try:
        result = yield do_blocking_task()
     except:
        print "Exception raised in thread"

     print "Thread returned", result

The threaded decorator also supports a async kwarg, which is by default True.
When True, the decorated function returns a :class:`~kaa.ThreadInProgress`
object. When False, however, invocation of the function blocks until the
decorated function completes, and its return value is passed back.  Internally,
the decorator merely invokes :meth:`~kaa.InProgress.wait` on the InProgress
returned by the threaded function, which means the main loop is otherwise kept
alive for timers and I/O handlers.  This allows a threaded function to be used
as a standard callback (but in practice it is not used often).

.. autofunction:: kaa.threaded

As a rule of thumb, if you have a function that must always be called
in the main thread, you would use ``@kaa.threaded(kaa.MAINTHREAD)`` as
mentioned above. If you need to decide case-by-case, don't decorate it
and use :class:`~kaa.MainThreadCallable` when needed.


The synchronized decorator
--------------------------

.. autoclass:: kaa.synchronized

Some functions may need to block concurrent access to certain
data structures, or prevent concurrent entry to the whole function.  In these
cases, ``kaa.synchronized`` can be used, which serves as both a decorator as
well as a context manager for use with Python's ``with`` statement::
   
    class Test(object):

        def foo(self):
            # call to do_something() can be done concurrently by other threads.
            do_something()
            with kaa.synchronized(self):
                # Anything in this block however is synchronized between threads.
                do_something_else()


        # bar() is a protected function
        @kaa.synchronized()
        def bar(self, x, y):
            do_something_else()

The decorator will synchronize on the actual object. Two different
objects can access the same function in two threads. On the other hand
it is not possible that one thread is in the protected block of `foo`
and another one calling `bar`.

The decorator can also be used for functions outside a class. In that
case the decorator only protects this one function. If more functions
should be protected against each other, a Python RLock object can be
provided::

  # threading.Lock does NOT work
  lock = threading.RLock()

  @kaa.synchronized(lock)
  def foo():
      # foo and bar synchronized
      do_something()

  @kaa.synchronized(lock)
  def bar(x):
      # foo and bar synchronized
      do_something()

  @kaa.synchronized()
  def baz():
      # only_baz_synchronized
      do_something()



Thread Functions
----------------

The following thread-related functions are available:

.. autofunction:: kaa.is_mainthread

.. autofunction:: kaa.main.wakeup

.. autofunction:: kaa.register_thread_pool

.. autofunction:: kaa.get_thread_pool


Callables and Supporting Classes
--------------------------------

Kaa provides a :class:`~kaa.ThreadCallable` class which can be used to invoke a
callable in a new thread every time the ThreadCallable object is invoked.

With the :class:`~kaa.ThreadPoolCallable` class, invocations are queued and
each executed in an available thread within a pool of one or more threads. A
priority may also be specified, and ThreadPoolCallable objects with the highest
priority are first in the queue (and hence executed first). This allows you to
create a priority-based job queue that executes asynchronously.

Although the :func:`@kaa.threaded() <kaa.threaded>` decorator provides a more
convenient means to make use of these classes, they may still be used directly.

Instances of the two classes above are callable, and they return
:class:`~kaa.ThreadInProgress` objects::

    def handle_result(result):
        # This runs in the main thread.
        print 'Thread returned with', result

    kaa.ThreadCallable(do_blocking_task)(arg1, arg2).connect(handle_result)

Or, alternatively::

    @kaa.coroutine()
    def some_coroutine():
        [...]
        result = yield kaa.ThreadCallable(do_blocking_task)(arg1, arg2)
    

.. kaaclass:: kaa.ThreadInProgress
   :synopsis:

   .. automethods::
      :remove: active
   .. autoproperties::

.. kaaclass:: kaa.ThreadCallable
   :synopsis:

   .. automethods::
   .. autoproperties::
   .. autosignals::

.. kaaclass:: kaa.ThreadPool
   :synopsis:

   .. automethods::
   .. autoproperties::
   .. autosignals::

.. kaaclass:: kaa.ThreadPoolCallable
   :synopsis:

   .. automethods::
   .. autoproperties::
   .. autosignals::


.. kaaclass:: kaa.MainThreadCallable

   The MainThreadCallable ensures that the wrapped function or method is executed
   via main loop.  The thread calling this function will return immediately after
   calling the MainThreadCallable, without waiting for the result. Invoking
   MainThreadCallables always returns an InProgress object::
   
     def needs_to_be_called_from_main(param):
         print param
         return 5
   
     # ... suppose we are in a thread here ...
     cb = kaa.MainThreadCallable(needs_to_be_called_from_main)
     print cb(3).wait()

   .. autosynopsis::

      .. automethods::
      .. autoproperties::
      .. autosignals::