Commits

Floris Bruynooghe committed d3beb1d

Add docstrings

  • Participants
  • Parent commits 775a6ad

Comments (0)

Files changed (2)

 # HG changeset patch
 # Date 1314394985 -3600
 # User Floris Bruynooghe <flub@devork.be>
-# Parent 02296bafbdd56781a63ade4f51b33c804d8e8a03
+# Parent 4941874babc766dd6647b7d99e8fa535c6dd87be
 ThreadPool class based on xthread
 
 diff --git a/eventlet/xtpool.py b/eventlet/xtpool.py
 new file mode 100644
 --- /dev/null
 +++ b/eventlet/xtpool.py
-@@ -0,0 +1,103 @@
+@@ -0,0 +1,123 @@
 +"""Threadpool to execute blocking calls
 +
 +This differs in eventlet.tpool in that the threadpool is encapsulated
 +
 +
 +class ThreadPool(object):
++    """Threadpool class to execute blocking calls
++
++    An instance of this class has a number of worker threads which you
++    can submit blocking functions too from inside a
++    greenlet/greenthread.  Each instance has it's own threadpool, the
++    size of wich you can specify using the ``nthreads`` parameter.
++    """
 +
 +    def __init__(self, nthreads=20):
 +        self._reqq = xthread.Queue()
 +            self._threads.append(t)
 +
 +    def execute(self, meth, *args, **kwargs):
++        """Execute a function in a worker thread"""
 +        msg = xthread.Message()
 +        self._reqq.put((msg, meth, args, kwargs))
 +        return msg.wait()
 +                msg.send(rv)
 +
 +    def killall(self):
++        """Kill all threads in this worker pool
++
++        The threads will continue to execute their current function,
++        if any.  After calling this no more methods will be executed
++        and subsequent calls to .execute() will hang.
++        """
 +        n_alive = len([t for t in self._threads if t.isAlive()])
 +        for i in xrange(n_alive):
 +            self._reqq.put(None)
 +
 +    def join(self, timeout=None):
++        """Wait until all threads have finished
++
++        After calling .killall() you can use this method to join all
++        the worker threads.  Ensuring no threads are left behind.
++        """
 +        if timeout is None:
 +            for t in self._threads:
 +                t.join()
 +            return not any([t.is_alive() for t in self._threads])
 +
 +    def is_alive(self):
++        """Return whether any workers are still active"""
 +        return any([t.is_alive() for t in self._threads])
 +
 +    def __del__(self):
 new file mode 100644
 --- /dev/null
 +++ b/eventlet/xthread.py
-@@ -0,0 +1,561 @@
+@@ -0,0 +1,623 @@
 +"""Cross-thread syncronisation primitives for eventlet
 +
 +This contains various syncronisation primitives for use with eventlet.
 +
 +
 +class Event(object):
++    """Cross greenlet/thread Event
++
++    This follows the threading.Event() interface.  See those docs.
++    """
 +    __slots__ = ('_notif', '_flag')
 +
 +    def __init__(self, hubcache=GLOBAL_HUBCACHE):
 +        self._flag = False
 +
 +    def is_set(self):
++        """Return whether the internal event flag is set"""
 +        return self._flag
 +
 +    def set(self):
++        """Set the internal event flag
++
++        This will wake up all calls which are .wait()ing on this event.
++        """
 +        self._flag = True
 +        self._notif.notify_all()
 +
 +    def clear(self):
++        """Reset the internal event flag to false"""
 +        self._flag = False
 +
 +    def wait(self, timeout=None):
++        """Wait until the internal flag is set
++
++        This returns immediately if the flag was already set, blocks
++        otherwise.
++        """
 +        waiter = self._notif.create_waiter()
 +        if self._flag:
 +            self._notif.cancel_waiter(waiter)
 +
 +
 +class Lock(object):
++    """Cross greenlet/thread Lock
++
++    This follows the threading.Lock() interface.  See those docs.
++    """
 +    __slots__ = ('hubcache', '_notif', '_lock', 'owner')
 +
 +    def __init__(self, hubcache=GLOBAL_HUBCACHE):
 +
 +
 +class RLock(Lock):
++    """Cross greenlet/thread recursive lock
++
++    This follows the threading.RLock() interface, see those docs.
++    """
 +
 +    def __init__(self, hubcache=GLOBAL_HUBCACHE):
 +        Lock.__init__(self, hubcache=hubcache)
 +
 +
 +class Message(object):
-+    """This is like eventlet.event.Event but cross-thread safe"""
++    """Single-use cross greenlet/thread message
++
++    This is like eventlet.event.Event but safe to use to communicate
++    between threads and greenlets.
++    """
 +    __slots__ = ('_sending', '_evt', '_msg', '_exc')
 +
 +    def __init__(self, hubcache=GLOBAL_HUBCACHE):
 +        self._exc = None
 +
 +    def ready(self):
++        """Whether the message was already sent"""
 +        return self._evt.is_set()
 +
 +    def send(self, result=None, exc=None):
++        """Send a message
++
++        Either send a normal object using the ``result`` parameter or
++        raise an exception in the waiter(s) using ``exc`` which takes
++        a 3-tuple as retrieved from sys.exc_info().
++        """
 +        self._sending.acquire()
 +        try:
 +            if self._evt.is_set():
 +            self._sending.release()
 +
 +    def send_exception(self, *args):
++        """Raise an exception in the waiter(s)
++
++        The argumens are the type, value and traceback objects as
++        returned by sys.exc_info().
++        """
 +        self.send(None, args)
 +
 +    def wait(self, timeout=None):
++        """Retrieve the value sent, blocking if not yet available
++
++        This will return the result sent using .send().  If an
++        exception was sent the exception will be raised here.
++        """
 +        self._evt.wait()
 +        if self._exc:
 +            type, val, tb = self._exc
 +
 +
 +class Condition(object):
++    """Cross greenlet/thread condition object
++
++    This follows the threading.Condition() interface, see those docs.
++    """
 +    __slots__ = ('_lock', '_notif')
 +
 +    def __init__(self, lock=None, hubcache=GLOBAL_HUBCACHE):
 +
 +
 +class BaseQueue(object):
++    """Base queue for xthread
++
++    This is an internal object used to build the Queue, PriorityQueue
++    and LifoQueue objects.  You porbably want to use one of those
++    instead of this, unless you have your own custom Queue class which
++    you want to make cross-thread safe.
++    """
 +
 +    def __init__(self, maxsize=0, hubcache=GLOBAL_HUBCACHE):
 +        self.hubcache = hubcache
 +
 +
 +class Queue(BaseQueue, queue.Queue):
++    """Cross greenlet/thread Queue object
++
++    You can use this queue to put and get items from both threads and
++    greenlets.
++    """
 +    pass
 +
 +
 +class PriorityQueue(BaseQueue, queue.PriorityQueue):
++    """Cross greenlet/thread PriorityQueue object"""
 +    pass
 +
 +
 +class LifoQueue(BaseQueue, queue.LifoQueue):
++    """Cross greenlet/thread LifoQueue Object"""
 +    pass
 diff --git a/tests/xthread_test.py b/tests/xthread_test.py
 new file mode 100644