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




    ----------------------------------------------------------------
    This message was sent using IMP, the Internet Messaging Program.
     
    Ajay, Sep 30, 2004
    #1
    1. Advertising

  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

    Ajay wrote:
    > 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

    [snip]
     
    Remco Boerma, Sep 30, 2004
    #2
    1. Advertising

  3. Ajay

    Bryan Olson Guest

    Ajay wrote:
    > i have an application that runs on a pocket pc.

    [...]
    > my question is, in terms of memory and processing
    > power, how much overhead will creating threads cost.


    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

    Remco Boerma wrote:
    > 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.

    What happens if all three threads are blocked, perhaps waiting
    for server_b, when a new request comes in?


    --
    --Bryan
     
    Bryan Olson, Oct 1, 2004
    #4
  5. Ajay

    Remco Boerma Guest

    Hi,

    Bryan Olson wrote:
    > Remco Boerma wrote:
    > > 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.
    >
    > What happens if all three threads are blocked, perhaps waiting
    > for server_b, when a new request comes in?


    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

    Remco Boerma wrote:
    > Bryan Olson wrote:
    >> Remco Boerma wrote:
    >> > 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.

    >>
    >> What happens if all three threads are blocked, perhaps waiting
    >> for server_b, when a new request comes in?

    >
    > 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.


    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.

    > 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.


    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. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Brendan Lynskey

    Low-cost ASIC tools

    Brendan Lynskey, Sep 26, 2003, in forum: VHDL
    Replies:
    2
    Views:
    2,056
    Jerry
    Sep 27, 2003
  2. Mr. x

    cost of SSL on the client

    Mr. x, Dec 2, 2003, in forum: ASP .Net
    Replies:
    3
    Views:
    358
    Mr. x
    Dec 3, 2003
  3. =?ISO-8859-2?Q?Przemys=B3aw_R=F3=BFycki?=

    What's the cost of using hundreds of threads?

    =?ISO-8859-2?Q?Przemys=B3aw_R=F3=BFycki?=, Mar 1, 2005, in forum: Python
    Replies:
    11
    Views:
    505
  4. Replies:
    3
    Views:
    969
    Pierre Barbier de Reuille
    Aug 29, 2005
  5. Sebastian

    Cost of creating objects?

    Sebastian, Aug 7, 2013, in forum: Java
    Replies:
    21
    Views:
    535
    Arved Sandstrom
    Aug 8, 2013
Loading...

Share This Page