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 NamedThreadCallback, and invocations of that function are queued to be executed in a single thread. 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 ThreadCallback so that each invocation is executed in a separate thread. Because these callbacks returns ThreadInProgress objects, which are derived from InProgress, they may be yielded from 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 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 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).
The decorator makes sure the function is always called in the thread with the given name. The function will return an InProgress object if async=True (default), otherwise it will cause invoking the decorated function to block (the main loop is kept alive) and its result is returned. If progress is True, the first argument to the function is an InProgressStatus object to return execution progress.
If name=kaa.MAINTHREAD, the decorated function will be invoked from the main thread. (In this case, currently the priority kwarg is ignored.)
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 MainThreadCallback when needed.
synchronized decorator and with statement similar to synchronized in Java. When decorating a non-member function, a lock or any class inheriting from object may be provided.
Parameters: |
|
---|
Create a synchronized object. Note: when used on classes a new member _kaa_synchronized_lock will be added to that class.
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()
The following thread-related functions are available:
Return True if the current thread is the main thread.
Note that the “main thread” is considered to be the thread in which the kaa main loop is running. This is usually, but not necessarily, what Python considers to be the main thread. (If you call kaa.main.run() in the main Python thread, then they are equivalent.)
Kaa provides a ThreadCallback class which can be used to invoke a callback in a new thread every time the ThreadCallback object is invoked.
With the NamedThreadCallback class, invocations are queued and each executed in the same thread. A priority may also be specified, and NamedThreadCallback objects with the highest priority is first in the queue (and hence executed first). This allows you to create a priority-based job queue that executes asynchronously.
Instances of the two classes above are callable, and they return ThreadInProgress objects:
def handle_result(result):
print "Thread returned with", result
kaa.ThreadCallback(do_blocking_task)(arg1, arg2).connect(handle_result)
kaa.Signal
kaa.Object
└─ kaa.InProgress
└─ kaa.ThreadInProgress
abort() | Aborts the callback being executed inside a thread. (Or attempts to.) |
---|
active | read-only | True if the callback is still waiting to be processed. |
---|
Aborts the callback being executed inside a thread. (Or attempts to.)
Invocation of a ThreadCallback or NamedThreadCallback will return a ThreadInProgress object which may be aborted by calling this method. When an in-progress thread is aborted, an InProgressAborted exception is raised inside the thread.
Just prior to raising InProgressAborted inside the thread, the abort signal will be emitted. Callbacks connected to this signal are invoked within the thread from which abort() was called. If any of the callbacks return False, InProgressAborted will not be raised in the thread.
It is possible to catch InProgressAborted within the thread to deal with cleanup, but any return value from the threaded callback will be discarded. It is therefore not possible abort an abort. However, if the InProgress is aborted before the thread has a chance to start, the thread is not started at all, and so obviously the threaded callback will not receive InProgressAborted.
Warning
This method raises an exception asynchronously within the thread, and this is unreliable. The asynchronous exception may get inadvertently cleared internally, and if it doesn’t, it will in any case take up to 100 bytecodes for it to trigger within the thread. This approach still has uses as a general-purposes aborting mechanism, but, if possible, it is preferable for you to implement custom logic by attaching an abort handler to the ThreadCallback or NamedThreadCallback object.
Notifier aware wrapper for threads. When a thread is started, it is impossible to fork the current process into a second one without exec both using the main loop because of the shared _thread_notifier_pipe.
Parameters: |
|
---|
kaa.Object
kaa.Callback
└─ kaa.thread.ThreadCallbackBase
└─ kaa.ThreadCallback
wait_on_exit | read/write | If True (default), wait for the thread on application exit. |
---|
abort | Emitted when the thread callback is aborted. |
---|
Emitted when the thread callback is aborted.
See abort() for a more detailed discussion.
Handlers may return False to prevent InProgressAborted from being raised inside the thread. However, the ThreadInProgress is still considered aborted regardless. Handlers of this signal are intended to implement more appropriate logic to cancel the threaded callback.
A callback to run a function in a thread. This class is used by the threaded decorator, but it is also possible to use this call directly.
kaa.Object
kaa.Callback
└─ kaa.thread.ThreadCallbackBase
└─ kaa.NamedThreadCallback
abort | Emitted when the thread callback is aborted. |
---|
Emitted when the thread callback is aborted.
See abort() for a more detailed discussion.
Handlers may return False to prevent InProgressAborted from being raised inside the thread. However, the ThreadInProgress is still considered aborted regardless. Handlers of this signal are intended to implement more appropriate logic to cancel the threaded callback.
The MainThreadCallback is a callback that will be executed from the main loop. The thread calling this function will return immediately after calling the object without waiting for the result. Invoking MainThreadCallbacks 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.MainThreadCallback(needs_to_be_called_from_main)
print cb(3).wait()
Callback that is invoked from the main thread.
Parameters: |
|
---|
kaa.Callback
└─ kaa.MainThreadCallback