cost of creating threads

Discussion in 'Python' started by Ajay, Sep 30, 2004.

  1. Ajay

    Ajay Guest

    hi!

    i have an application that runs on a pocket pc. the application has a
    server which responds to UDP requests. each request contains the address
    of another server (say, server_b). the pocket pc server recieves these UDP
    requests and creates an SSL client connection to sercer_b

    my current setup is iterative and i am thinking of making it into a
    threaded application.since i have a gui, the pocket pc server already runs
    in a separate thread. my question is, in terms of memory and processing
    power, how much overhead will creating threads cost. My sessions are quite
    short lived. if this was a pc application, i'd go ahead with a threads. But
    since this is a pocket pc (the processor is a XScale 400 MHz but really all
    said and done we only ever have around 200 MHz or so - memory available
    would be optimistically speaking, around 12 MB)

    any thoughts on what threads would cost me?

    thanks

    cheers
     
    Ajay, Sep 30, 2004
    #1
    1. Advertisements

  2. Ajay

    Remco Boerma Guest

    hi,

    In the documentation is a short comprehensive list of what server
    options for handling connections are usefull in what situations. .
    See chapter 15.1.2 on http://www.cherrypy.org/static/html/tut/node17.html .
    While you have a tiny server, i would recommend a thread-pool of about 2
    to 3 threads. This at least cuts down the time needed for thread creation.

    Cheers!
    Remco
    [snip]
     
    Remco Boerma, Sep 30, 2004
    #2
    1. Advertisements

  3. Ajay

    Bryan Olson Guest

    I've never worked with Pocket-PC, but the answer is almost
    certainly "not much". You can get reasonable bounds with simple
    test programs. I'll include a Python thread creation timer
    below.

    Threading has improved vastly in recent years, and the current
    versions of the popular operating systems now have excellent
    thread support. As one might expect, out-dated ideas about
    the cost of threads are still widespread.


    --Bryan



    import thread
    import time

    lock = thread.allocate_lock()
    lst = [0]

    def increment():
    lock.acquire()
    lst[0] += 1
    lock.release()

    def mass_thread(nthreads):
    print "Running %d threads..." % nthreads
    i = 0
    benchmark = time.clock()
    while i < nthreads:
    try:
    thread.start_new_thread(increment, ())
    i += 1
    except:
    # thread.error is undocumented, so catch all
    time.sleep(0.05)
    go = 1
    while go:
    time.sleep(0.1)
    lock.acquire()
    if lst[0] == nthreads:
    go = 0
    lock.release()
    benchmark = time.clock() - benchmark
    print "All %s threads have run." % lst[0]
    print "That took %f seconds." % benchmark

    if __name__ == '__main__':
    mass_thread(10000)
     
    Bryan Olson, Sep 30, 2004
    #3
  4. Ajay

    Bryan Olson Guest

    http://www.cherrypy.org/static/html/tut/node17.html .
    creation.

    What happens if all three threads are blocked, perhaps waiting
    for server_b, when a new request comes in?
     
    Bryan Olson, Oct 1, 2004
    #4
  5. Ajay

    Remco Boerma Guest

    Hi,

    I guess it would indeed wait until one of the first 3 threads has closed
    it's connection, or a timeout occurs. But you ought to test it, just to
    make sure. . With a little statistics usage, you would be able to create
    new threads on the fly if many connections are established in a short
    time, releasing the threads when idle for x seconds. . This would allow
    you to use more resources when needed, and releasing them when done.

    I don't have any knowledge of pocket pc's, but is there any way you can
    use twisted? I've read/heared it's master using only a single thread. .

    Cheers!
     
    Remco Boerma, Oct 3, 2004
    #5
  6. Ajay

    Bryan Olson Guest

    I think you are basically right; that is how most thread-pools
    work. I've concluded that statically-sized thread-pools are
    usually a mistake.
    That sounds like a reasonable idea, but doing it efficiently
    could be tricky. The most straightforward Python implementation
    would probably use the locks-with-timeout in Python's
    'threading' module. The way these are implemented, any positive
    timeout means the thread actually goes into a sleep-and-poll
    loop. Keeping a pool this way could be significantly less
    efficient than creating each thread on demand.

    Most descriptions of thread-pools imply that their primary
    purpose is to avoid the overhead of creating and destroying
    threads. In fact, thread pools can provide other services, and
    the efficiency motivation is dim and fading. I posted a program
    that times creation of thousands of threads, and running it
    shows that modern PC-class machines with modern cheap/free OS's
    can create a few thousand threads per second. Coding in C speeds
    that up by a factor of a several. If a program needs dozens, or
    even hundreds, of threads every second, it can simply create
    them as needed. No sense solving problems we don't have.

    A clever operating system can keep a cache of threads in the
    background. The system can probably make better decisions on
    when to create a new thread than can the application programmer.
    Do I have runable threads, or are they all blocked? If some
    thread calls to create another thread, I should create it if all
    the current threads are blocked. Otherwise, let the runnable
    threads run; if they finish then they can then take on the new
    tasks.


    Sticking with my time-it-and-see approach, I wrote a simple
    thread cache to see how much diffence it makes in my thousands-
    of-threads timer. On my PC, it speeds it up by a factor of five
    or six. In my timer, each thread does almost nothing, and the
    more work a thread does the less difference creation time makes.
    Still there may be cases where thread creation uses a
    significant portion of run-time, and the cache does speed things
    up.

    My thread cache doesn't limit the total number of threads.
    Instead, it limits the number waiting in the cache. When the
    client calls for a thread, if one or more threads is in the
    cache, it takes one of those; if not, it (tries to) create a new
    one. When a thread is finished with its task, it checks how
    many others are waiting in the cache, and decides whether to
    exit or cache itself.

    For ease of integration, I wrote it as a module that supports
    the same interface as the Python library's 'thread' module. A
    program can simply "import thread_cache as thread". It's new,
    so it's not well-tested.


    --Bryan


    """
    Module thread_cache.py
    Same interface as Python library's thread module (which
    it uses), but it keeps a cache of threads.
    """

    max_nwaiting = 20

    from thread import *

    _task = None
    _mutex = allocate_lock()
    _vacant = allocate_lock()
    _occupied = allocate_lock()
    _occupied.acquire()
    _nwaiting = 0
    _start = start_new_thread

    def _run():
    global _nwaiting, _task
    go = 1
    while go:
    _occupied.acquire()
    _mutex.acquire()
    (func, args, kwargs) = _task
    _task = None
    _mutex.release()
    _vacant.release()
    func(*args, **kwargs)
    # Thread might exit with an exception, which is fine.
    _mutex.acquire()
    if _nwaiting < max_nwaiting:
    _nwaiting += 1
    else:
    go = 0
    _mutex.release()

    def start_new_thread(func, args=(), kwargs={}):
    global _nwaiting, _task
    _vacant.acquire()
    _mutex.acquire()
    if not _nwaiting:
    try:
    _start(_run, (), {})
    except:
    _mutex.release()
    _vacant.release()
    raise
    _nwaiting += 1
    _task = (func, args, kwargs)
    _nwaiting -= 1
    _mutex.release()
    _occupied.release()
     
    Bryan Olson, Oct 5, 2004
    #6
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.