Threading in Django

Profitable use of threading in web development is rare, particularly when contending with Python’s global interpreter lock. There are a few notable exceptions to this.

The global interpreter lock (GIL) is the method that Python uses to maintain internal thread-safety when not all Python objects are thread-safe. The GIL ensures that no Python object may be modified by multiple threads at the same time. This is transparent to the Python programmer; the GIL is locking internal structures. A list that is modified by multiple threads without explicit locking will still behave erratically.

This makes threading less useful in web development. Because Python can not directly maintain state between reqeusts (indirectly, via the client, state may be maintained using session cookies or other similar strategies), each request is a new thread:

 1. Determine what data is being requested
 2. Get the data
 3. Format the data
 4. Send the data

Each of these steps depends on the state information from the previous step. There is not a lot of room for asynchronicity. The usefulness of threading is pushed back to the web server. That is where integrated server/framework solutions, like Ocsigen, have an advantage.

Many web-based applications, however, are not simple database front ends. There are a few common situations where threading becomes useful; specifically, when there are side effects of a request.

On a side note, experts will tell you that only POST request should result in side effects. This is misleading. POST should certainly be used for user-intended side effects. However, what happends when there is an error loading a page?

Error messages

In the event of a coding or environment error, Django sends me an email. This is a wonderful (and an occassionally annoying) feature. But what if the problem is caused by the data we input, rather than the code? I can detect this in my code and present the user with a nice error page apologizing for the inconvenience, but now I want to notify the content team that an entry in the database is invalid in some way.

Sending a message, especially if Django is connecting to a remote mail server, can take a while. This is a good use for threading. The thread should deal with as little data processing as possible, concentrating instead on the side effect.

import threading
from django.core.mail import send_mail
 
def foo(request, identifier):
    data = get_some_data(identifier)
    try:
        error_check(data) # raise exception if data invalid
    except InvalidData, e:
        # Format our information here, in the main thread
        subject = "Invalid data in entry %d" % identifier
        message = """
            There is an error in entry %d.  Please check this
            data at http://path/to/django/admin/app/table/%d.
        """ % (identifier, identifier)
        recipients = ['someone@somewere.com', 'someoneelse@somewhere.com']
        from = 'root@server.com'
 
        # Create a new thread in Daemon mode to send message
        t = threading.Thread(target=send_mail,
                             args=[subject, message, from, recipients],
                             kwargs={'fail_silently': True})
        t.setDaemon(True)
        t.start()
    return HttpResponseServerError(some_error_page)

Note particularly that we use t.setDaemon(True) on the thread before starting it. This tells Python not to wait for the thread to exit before returning data to the client.

Writing files

Many of our web-based programs write data to static files. Some applications maintain logs. Others publish static HTML files to the enterprise server. These are great uses for Python threads, since the GIL is released during file IO operations.

Caching remote data

We are a large business and applications are developed by various (often isolated) units. I often find myself in a situation where my application depends on mutable data extracted from another system but does not have direct access to the data’s database.

Rather than depend on low internal network latencies and download the data extract on each page load, I cache the data and keep a local copy, using a script to synchronize the data. For simple data, this can be stored using Django’s low level cache. But if some state needs to be maintained for that data, a database table is a better method.

When there are a large number of such objects, a scheduled update process becomes burdensome, especially if the number of objects increases regularly. Therefore, the solution is to trigger the event when the data is accessed (via a page load).

Each cached database entry gets a timestamp field to note its last update. The model defines an update method and the model manager’s get() method checks the entry’s timestamp to see if the data needs to be freshened. The update routine is called in a separate thread.

Warning: in Django, when a model instance is found via a relationship, the manager’s get() method is not called! This is because these objects are accessed via a django.db.models.fields.related.ManyRelatedManager, rather than the model’s own manager. If you wish to solve this without duplicating code, look into Django signals.

The problem is that this is not a simple side effect and the GIL will get in the way. The solution is to do all of the necessary logic to determine if the object needs to be updated in the main thread. Just before returning the response to the user, the update thread is started in Daemon mode. That minimizes competition for the GIL. The user will not get the updated version of the object on this page load, but the next user will.

The other alternative is to use os.fork or the subprocess module to launch the update routine in a separate process (with its own interpreter instance and its own GIL). This sort of solution gets used a lot in PHP because of its lack of threads. In Python, threads tend to be more useful and much less resource hungry.

Mar 7th, 2008 | Posted in Software
  1. Robert
    May 25th, 2009 at 10:07 | #1

    Hi, I found your article useful, but also I found some errors ;) (from -> from_, kwargs={‘fail_silently’=True} -> kwargs={‘fail_silently’:True}). I made function similar to django.core.mail.send_mail:


    import threading

    def async_send_mail(subject, message, from_, recipients):
    """
    based on:
    http://www.artfulcode.net/articles/threading-django/
    returns true allways
    """
    from django.core.mail import send_mail

    # Create a new thread in Daemon mode to send message
    t = threading.Thread(target=send_mail,
    args=[subject, message, from_, recipients],
    kwargs={'fail_silently':True})
    t.setDaemon(True)
    t.start()
    return True

  2. Sep 27th, 2009 at 18:28 | #2

    Hi, your article is just what I have been looking for.
    I translated into Japanese in my site since it’s great.
    Thank you for good article!

  3. RawNawpairm
    Jan 1st, 2010 at 15:01 | #3

    In my program I need to select multiple bytes, I have the first and last byte being 0×18 and 0×28. I’m editing a txt file. I have it so whatever I put in is replaced. So I have myfile.seekg ( hexvalues = (0×18, 0×19, 0×20, etc.) You get the point. I want to just put in 0×18 and 0×28 and it gets everything in the middle. Im using fstream

    _____________
    Darmowe tapety

  4. Feb 14th, 2010 at 19:46 | #4

    ecommerce developers

    osCommerce Developers

    Does your firm need ecommerce programmers? Our firm is the right place for your osCommerce development requirements! Our developers have spent upto 10 years on development. Our ecommerce developers can get you started right away.

    Do you want a shopping cart?

    Stability + Security + Speed = osCommerce. Rapidly develop your ecommerce website with osCommerce. We have experience with many areas of shopping cart websites. Our developers will pin point the exact osCommerce module for your requirements and get the job you need done very quickly.

    Need answers our developers can get them to you

    Have an existing shopping cart and need an upgrade by our expert osCommerce development service?

    NetTrackers also offers upgrade services for your exisiting ecommerce website. Our ecommerce development team can tweak your existing store design and turn into a world class ecommerce property. We also offer additional optimization services to make your online shopping business a success.

    Contact us to see how we can get you up and running quickly and inexpensively.

    Additional Services – Complete Solutions

    In addition to osCommerce development, NetTrackers also provides many other services, including oscommerce customization, oscommerce modules development, oscommerce templates development and related consulting.

  5. Feb 15th, 2010 at 02:10 | #5

    osCommerce Programmer

    osCommerce Developers

    Do you need osCommerce Developers? NetTrackers is the perfect place for your osCommerce development requirements! We have succesfully been developing the osCommerce shopping cart program since 2000. We have osCommerce Expert Developers that can assist in your osCommerce website develoment immediately.

    Need osCommerce installed?

    osCommerce is an extremely stable and well used GPL shoping cart. osCommerce helps in rapid e-commerce website development. With years of experience we can assist you in varied areas of website development. Our developers will pin point the exact osCommerce module for your requirements and get the job you need done very quickly.

    Whats your question – We can help you out with them

    Have an existing shopping cart and need an upgrade by our expert osCommerce development service?

    NetTrackers also offers upgrade services for your exisiting ecommerce website. Our ecommerce development team can tweak your existing store design and turn into a world class ecommerce property. We also offer additional optimization services to make your online shopping business a success.

    Contact us to see how we can get you up and running quickly and inexpensively.

    Additional Services – Complete Solutions

    In addition to osCommerce development, NetTrackers also provides many other services, including oscommerce customization, oscommerce modules development, oscommerce templates development and related consulting.

  6. Mar 1st, 2010 at 19:49 | #6

    ndumarket.com is an online trading platform for African food shops and other products in the U.S and Canada.

    ndumarket.com exhibits a variety of African food products from African stores and African Markets owners who are committed to better and quicker client service.

  7. Mar 9th, 2010 at 08:42 | #7

    Aloha! Dis web-site is da champion, and I have been looking for this website for a while now and I’m so fortunate I finally found it.

    I am 23 years of age and finishing my masters at Houston.

    I’m the type of guy who enjoys to taste different things. Presently I am beginning my best E project. I’m doing it all alone without the help of someone. I am utilizing the net as the only way to acheive this. I ran across a very unbelievable blog that explains how to do internet business and website marketing. There is a place on the net that covers all the steps involved in get rich online.

    I am not sure about how accurate the information given there iz. If some guys right here who had experience with these techniques can have a look and give your feedback in the thread it would be grand and I’d extremely value it, cause I really take an interest in almost all of the stuff on this internet site called making easy money online.

    Thanks for your time. You dudes are great.

Leave a comment

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">