threading.local

36 views
Skip to first unread message

William Dode

unread,
Oct 2, 2008, 12:36:21 PM10/2/08
to mod...@googlegroups.com
Hi,

In daemon mode, with threads=1 :

def application(environ, start_response):

status = '200 OK'
output = "con= %s" % cgi.escape(repr(pool.connection()))
loc = threading.local()
try:
loc.i += 1
except AttributeError:
loc.i = 0
output = 'i=%s' % loc.i

response_headers = [('Content-type', 'text/html'), ]
start_response(status, response_headers)

return [output]

threading.local doesn't stay between requests. Is it normal ?

I found this with DBUtils wich doesn't reuse connection.

I missed something ?

--
William Dodé - http://flibuste.net
Informaticien Indépendant

Graham Dumpleton

unread,
Oct 2, 2008, 7:07:57 PM10/2/08
to mod...@googlegroups.com
2008/10/3 William Dode <wi...@flibuste.net>:

>
> Hi,
>
> In daemon mode, with threads=1 :
>
> def application(environ, start_response):
>
> status = '200 OK'
> output = "con= %s" % cgi.escape(repr(pool.connection()))
> loc = threading.local()
> try:
> loc.i += 1
> except AttributeError:
> loc.i = 0
> output = 'i=%s' % loc.i
>
> response_headers = [('Content-type', 'text/html'), ]
> start_response(status, response_headers)
>
> return [output]
>
> threading.local doesn't stay between requests. Is it normal ?
>
> I found this with DBUtils wich doesn't reuse connection.
>
> I missed something ?

If you want something to persist between requests, just make it a
global variable within the file, you do not need to use
threading.local(). Depending on type of data, global declaration may
be needed in function scope so that on assignment it doesn't just
create a local variable to function (which is what is happening now).

In doing this, if a multithreaded application you would however need
to protect using thread mutex locks any updates to the global data.
This is presuming all threads should share the global data. If each
thread should have its own, then threading.local() may be okay, but
you need to initialise it once outside of the function, actually at
global scope, not like what you are doing now.

BTW, also be careful of embedded mode as source code reloading could
cause issues in that case. See:

http://code.google.com/p/modwsgi/wiki/ReloadingSourceCode

Graham

William Dode

unread,
Oct 3, 2008, 4:46:50 AM10/3/08
to mod...@googlegroups.com
On 02-10-2008, Graham Dumpleton wrote:
>
> 2008/10/3 William Dode <wi...@flibuste.net>:
>>
>> Hi,
>>
>> In daemon mode, with threads=1 :
>>
>> def application(environ, start_response):
>>
>> status = '200 OK'
>> output = "con= %s" % cgi.escape(repr(pool.connection()))
>> loc = threading.local()
>> try:
>> loc.i += 1
>> except AttributeError:
>> loc.i = 0
>> output = 'i=%s' % loc.i
>>
>> response_headers = [('Content-type', 'text/html'), ]
>> start_response(status, response_headers)
>>
>> return [output]
>>
>> threading.local doesn't stay between requests. Is it normal ?
>>
>> I found this with DBUtils wich doesn't reuse connection.
>>
>> I missed something ?
>
> If you want something to persist between requests, just make it a
> global variable within the file, you do not need to use
> threading.local(). Depending on type of data, global declaration may
> be needed in function scope so that on assignment it doesn't just
> create a local variable to function (which is what is happening now).

I thought it's a singleton...

But even if i put it outside the function it doesn't show what i expect
:

import cgi
import threading
loc = threading.local()

def application(environ, start_response):

status = '200 OK'


try:
loc.i += 1
except AttributeError:
loc.i = 0

output = '%s i=%s' % (loc, loc.i)

response_headers = [('Content-type', 'text/html'), ]
start_response(status, response_headers)

return [cgi.escape(output)]

The output is everytime <thread._local object at 0xb710d6e0> i=0

>
> In doing this, if a multithreaded application you would however need
> to protect using thread mutex locks any updates to the global data.
> This is presuming all threads should share the global data. If each
> thread should have its own, then threading.local() may be okay, but
> you need to initialise it once outside of the function, actually at
> global scope, not like what you are doing now.

It seems that DBUtils.PersistentDB use threading.local() to keep one
connection for each thread. I cannot make it work with mod_wsgi...

>
> BTW, also be careful of embedded mode as source code reloading could
> cause issues in that case. See:
>
> http://code.google.com/p/modwsgi/wiki/ReloadingSourceCode

I use only deamon mode

thx

Graham Dumpleton

unread,
Oct 3, 2008, 4:56:15 AM10/3/08
to mod...@googlegroups.com
2008/10/3 William Dode <wi...@flibuste.net>:
>
> On 02-10-2008, Graham Dumpleton wrote:
>>
>> 2008/10/3 William Dode <wi...@flibuste.net>:
>>>
>>> Hi,
>>>
>>> In daemon mode, with threads=1 :
>>>
>>> def application(environ, start_response):
>>>
>>> status = '200 OK'
>>> output = "con= %s" % cgi.escape(repr(pool.connection()))
>>> loc = threading.local()
>>> try:
>>> loc.i += 1
>>> except AttributeError:
>>> loc.i = 0

Have you put debug statements in here to see whether that actually
fails with an exception and therefore puts it to 0 every time.

Add:

import sys
import os
print >> sys.stderr, "EXCEPT %s %s" % (os.getpid(), loc.i)

in the except block. Similarly with try block.

Also try using a simple variable like I said, with lots of debug and
see what happens in that case.

Debug will go to Apache error log.

Graham

William Dode

unread,
Oct 3, 2008, 5:43:10 AM10/3/08
to mod...@googlegroups.com
Maybe more clear :

#!/usr/bin/python
import cgi
import threading
import sys
import os

class MyLoc(threading.local):
def __init__(self):
print >> sys.stderr , 'init'

myloc = MyLoc()

def application(environ, start_response):
status = '200 OK'

myloc.i = 0
print >> sys.stderr, 'pid: %s id: %s id.__dict__: %s' % (os.getpid(), id(myloc), id(myloc.__dict__))
output = ''


response_headers = [('Content-type', 'text/html'), ]
start_response(status, response_headers)

return [cgi.escape(output)]

[Fri Oct 03 11:37:04 2008] [error] init
[Fri Oct 03 11:37:04 2008] [error] pid: 1836 id: 3067827220 id.__dict__: 3067884244
[Fri Oct 03 11:37:04 2008] [error] init
[Fri Oct 03 11:37:04 2008] [error] pid: 1836 id: 3067827220 id.__dict__: 3067885740
[Fri Oct 03 11:37:05 2008] [error] init
[Fri Oct 03 11:37:05 2008] [error] pid: 1836 id: 3067827220 id.__dict__: 3067884244
[Fri Oct 03 11:37:05 2008] [error] init
[Fri Oct 03 11:37:05 2008] [error] pid: 1836 id: 3067827220 id.__dict__: 3067885740

init should not be called and __dict__ should not be different

The same with wsgiref :
from wsgiref.simple_server import make_server
make_server('',8080,application).serve_forever()

init
pid: 1868 id: 3082036284 id.__dict__: 3082022260
pid: 1868 id: 3082036284 id.__dict__: 3082022260
pid: 1868 id: 3082036284 id.__dict__: 3082022260
pid: 1868 id: 3082036284 id.__dict__: 3082022260
pid: 1868 id: 3082036284 id.__dict__: 3082022260

I'll look if i can reproduce this with the code of _threading_local

William Dode

unread,
Oct 3, 2008, 5:50:23 AM10/3/08
to mod...@googlegroups.com
> I'll look if i can reproduce this with the code of _threading_local

With _threading_local it works (python implementation)

import _threading_local
class MyLoc(_threading_local.local):

[Fri Oct 03 11:47:08 2008] [error] init
[Fri Oct 03 11:47:08 2008] [error] pid: 2091 id: 3067888900 id.__dict__: 3067885876
[Fri Oct 03 11:47:08 2008] [error] pid: 2091 id: 3067888900 id.__dict__: 3067885876
[Fri Oct 03 11:47:09 2008] [error] pid: 2091 id: 3067888900 id.__dict__: 3067885876

Graham Dumpleton

unread,
Oct 3, 2008, 6:28:48 AM10/3/08
to mod...@googlegroups.com
One possibility is that although you think you are using daemon mode,
you aren't, and that Apache compiled with worker MPM. This can occur
if you don't have WSGIProcessGroup directive set properly to refer to
daemon process group setup using WSGIDaemonProcess.

Post the mod_wsgi bits of the Apache configuration, include any
VirtualHost, Directory, Location context they are defined in.

In your per request debug also print out:

print >> sys.stderr, environ.get('mod_wsgi.process_group')
print >> sys.stderr, environ.get('mod_wsgi.application_group')

print >> sys.stderr, environ.get('wsgi.multithread')
print >> sys.stderr, environ.get('wsgi.multiprocess')

If mod_wsgi.process_group prints out as empty string, you are running
in embedded mode. If multithread is true shows that running in
multithreaded process and not single threaded process as you expect
and thus also why result may be different each time.

You could also print out:

print >> sys.stderr, threading.currentThread()

to show what Python thinks the thread is each time.

Graham



2008/10/3 William Dode <wi...@flibuste.net>:

Graham Dumpleton

unread,
Oct 3, 2008, 7:43:42 AM10/3/08
to mod...@googlegroups.com
Hmmmm, I think I know why.

It is very interesting that no one has noticed or commented on this
behaviour before, although I also suspect I know why.

In mod_wsgi at the C code level, a new thread state object is created
for each request, with it being destroyed at the end of the request.
The threading.local() object is actually attached to this C thread
state object, but because the thread state object is destroyed at the
end of the request, so also is the threading.local() object.

Thus, for all intents and purposes, and as far as threading.local() is
concerned, to the application it looks like a brand new Python thread
instance is used for every request, even though the same foreign
thread, created outside of Python, can be used for multiple requests.

The reason no one has probably noticed is that normally people would
only want a threading.local() instance to exist for the life time of a
request. Frameworks should even deliberately delete attributes added
to the threading.local() object at the end of the request to ensure it
is cleared of anything.

FWIW, the way mod_wsgi works in this respect is actually the same as
mod_python. One would hope that no application is dependent on this
quirk of mod_python/mod_wsgi and they do always cleanup
threading.local() attributes at the end of the request. If they don't,
then when hosting on native Python web server, or fastcgi etc, the
code wouldn't necessarily work as threading.local() instance could be
polluted with attributes from previous request.

Anyway, this behaviour would be an issue for code which is trying to
use threading.local() as a shortcut to avoid having to do their own
thead mutex locking etc.

The thing is though, although mod_wsgi behaviour could be changed,
will still occur in mod_python. Also, there would be no guarantee in
any WSGI hosting mechanism that threads would be reused time and time
again to handle requests, so use of threading.local() in the way you
want may not be reliable anyway. I believe for example that CherryPy
will keep a pool of threads and may at its discretion create
additional threads if it thinks it needs more and then later destroy
threads if it thinks it has more than it needs. Thus in CherryPy as
well, although threads may get reused for a while, I think they also
may disappear and be replaced with new threads.

In summary, if one looks across different WSGI hosting mechanism,
given that the WSGI application object is the entry point for a
request and one cannot know how that will come to be called, I don't
think you could rely on data keyed to thread instance being preserved
across requests, with threading.local(). You also wouldn't want to key
itself based on the thread ID either as this may not be a fixed set
and if there is no way to cleanup when a thread is destroyed data from
anything keyed on thread ID, your application memory would just keep
growing with junk.

That all said, what are other peoples opinions on this? Yes I could
attempt to change code to remember thread state objects for Apache
foreign threads, since the number of threads is always constant and
they aren't deleted until process being killed, but would making this
change such that threading.local() persists across requests cause
problems for code out there? Leaving the behaviour as is, may actually
be better as it may protect better against applications which aren't
written to clear per thread state properly.

Comments?

Graham

2008/10/3 Graham Dumpleton <graham.d...@gmail.com>:

Graham Dumpleton

unread,
Oct 4, 2008, 7:19:27 AM10/4/08
to mod...@googlegroups.com
BTW, if I am right, you would see the behaviour you expect to see if you use:

WSGIApplicationGroup %{GLOBAL}

That is, force your application to run in main Python interpreter
instance within process.

This is because when using main interpreter mod_wsgi uses simplified
API for GIL so as to be compatible with third party C extension
modules that do the same. In that case Python internally manages the
thread state objects and so they get reused rather than fresh one
created each time.

gert

unread,
Oct 4, 2008, 7:36:44 PM10/4/08
to modwsgi
can threading.local() be used to create a permanent database
connection for each interpreter ?

Graham Dumpleton

unread,
Oct 4, 2008, 9:17:33 PM10/4/08
to mod...@googlegroups.com
2008/10/5 gert <gert.c...@gmail.com>:

>
> can threading.local() be used to create a permanent database
> connection for each interpreter ?

The threading.local() dictionary is specific to a thread within an interpreter.

As already explained though, because of how mod_wsgi is currently
implemented, this behaviour, ie., what you would see for command line
Python, only applies if forcing application to run in main
interpreter. That is, when have:

WSGIApplicationGroup %{GLOBAL}

Graham

gert

unread,
Oct 5, 2008, 10:06:59 AM10/5/08
to modwsgi
But how would you launch a mysql connection so i can do

loc = threading.local()
db = loc.db
db.execute("SELECT * FROM Graham",())

when WSGIApplicationGroup %{GLOBAL} is set


Graham Dumpleton

unread,
Oct 5, 2008, 10:14:30 AM10/5/08
to mod...@googlegroups.com
2008/10/6 gert <gert.c...@gmail.com>:

At a guess, something like:

import threading

local = threading.local()

def application(.....):

try:
db = local.db
except:
db = local.db = <stuff to create connection>

db.execute("SELECT documentation FROM manual",())

Graham

gert

unread,
Oct 5, 2008, 12:59:56 PM10/5/08
to modwsgi
>       db.execute("SELECT documentation FROM manual",())

lol Graham sending me background information here :-)

gert

unread,
Oct 5, 2008, 2:27:33 PM10/5/08
to modwsgi
it works can't wait to benchmark it :)

http://code.google.com/p/appwsgi/source/browse/trunk/www/lib/db.py

aldo i don't know if it really really works.
also i think the __del__ methode actually deletes it anyway every
request ?

gert

unread,
Oct 5, 2008, 5:07:12 PM10/5/08
to modwsgi

Graham Dumpleton

unread,
Oct 5, 2008, 8:34:02 PM10/5/08
to mod...@googlegroups.com
That is because you didn't read the example properly. The
threading.local() instance is meant to be at global scope in module.

# Global !!!!!!!
local = threading.local()

def application(environ, start_response):

try:
db = local.db
except:
local.db = _mysql.connect('127.0.0.1','root','root','www')
db = local.db

Graham

2008/10/6 gert <gert.c...@gmail.com>:

Graham Dumpleton

unread,
Oct 6, 2008, 4:00:08 AM10/6/08
to mod...@googlegroups.com
Actually, I am not thinking, as wouldn't make a difference where it is.

Graham

2008/10/6 Graham Dumpleton <graham.d...@gmail.com>:

gert

unread,
Oct 6, 2008, 4:11:19 AM10/6/08
to modwsgi
Failed requests: 9993 But I did have 1564.21 requests per second
doh :-)
anyway http://87.98.218.86/gil.py seem to work ?

http://87.98.218.86/bench.txt (added my apache.conf)

http://87.98.218.86/bench.htm

So did we find a gil bug in Grahams mighty code ?

Graham Dumpleton

unread,
Oct 6, 2008, 4:18:19 AM10/6/08
to mod...@googlegroups.com
2008/10/6 gert <gert.c...@gmail.com>:

No one will never know because you never post enough information. If
the script is generating a 500 error response, what was the traceback
or other error in the Apache error log? Have you tried to debug what
was causing the error?

Graham

gert

unread,
Oct 6, 2008, 4:33:36 AM10/6/08
to modwsgi
On Oct 6, 10:18 am, "Graham Dumpleton" <graham.dumple...@gmail.com>
wrote:
> 2008/10/6 gert <gert.cuyk...@gmail.com>:
>
> > Failed requests:        9993 But I did have 1564.21 requests per second
> > doh :-)
> > anywayhttp://87.98.218.86/gil.pyseem to work ?
>
> >http://87.98.218.86/bench.txt(added my apache.conf)
>
> >http://87.98.218.86/bench.htm
>
> > So did we find a gil bug in Grahams mighty code ?
>
> No one will never know because you never post enough information. If
> the script is generating a 500 error response, what was the traceback
> or other error in the Apache error log? Have you tried to debug what
> was causing the error?
>
> Graham

I have alooooot of this

[Mon Oct 06 09:56:02 2008] [error] [client 127.0.0.1] Traceback (most
recent cal l last):
[Mon Oct 06 09:56:02 2008] [error] [client 127.0.0.1] File "/srv/www/
gil.py", line 11, in application
[Mon Oct 06 09:56:02 2008] [error] [client 127.0.0.1]
db.query("SELECT test FROM test")
[Mon Oct 06 09:56:02 2008] [error] [client 127.0.0.1] InterfaceError:
(0, '')
[Mon Oct 06 09:56:02 2008] [error] [client 127.0.0.1] mod_wsgi
(pid=1134): Excep tion occurred
processing WSGI script '/srv/www/gil.py'.


Cool I noticed that pressing f5 it sometimes works and sometimes
doesn't lol :) :) :)

when it works i get

[Mon Oct 06 10:30:46 2008] [info] [client 80.200.216.121] mod_wsgi
(pid=1542, process='', application=''): Loading WSGI script '/srv/www/
gil.py'.

When it doesnt i get

[Mon Oct 06 09:56:02 2008] [error] [client 127.0.0.1] Traceback (most
recent cal l last):
[Mon Oct 06 09:56:02 2008] [error] [client 127.0.0.1] File "/srv/www/
gil.py", line 11, in application
[Mon Oct 06 09:56:02 2008] [error] [client 127.0.0.1]
db.query("SELECT test FROM test")
[Mon Oct 06 09:56:02 2008] [error] [client 127.0.0.1] InterfaceError:
(0, '')
[Mon Oct 06 09:56:02 2008] [error] [client 127.0.0.1] mod_wsgi
(pid=1134): Excep tion occurred
processing WSGI script '/srv/www/gil.py'.


William Dode

unread,
Oct 6, 2008, 5:09:17 AM10/6/08
to mod...@googlegroups.com
On 04-10-2008, Graham Dumpleton wrote:
>
> BTW, if I am right, you would see the behaviour you expect to see if you use:
>
> WSGIApplicationGroup %{GLOBAL}

More or less, it give me alternatively two differents local instances...

But i'm agree with your analyze, that to use threading.local is not
reliable. It's ok to keep the connection for the time of the request but
not for a persistent pool between requests. It's just to know about it.

The only problem is that there is not a lot of db pool utilities and
dbutils is one of the most famous...

gert

unread,
Oct 6, 2008, 5:24:07 AM10/6/08
to modwsgi
On Oct 6, 10:33 am, gert <gert.cuyk...@gmail.com> wrote:
> On Oct 6, 10:18 am, "Graham Dumpleton" <graham.dumple...@gmail.com>
> wrote:
>
> > 2008/10/6 gert <gert.cuyk...@gmail.com>:
>
> > > Failed requests:        9993 But I did have 1564.21 requests per second
> > > doh :-)
> > > anywayhttp://87.98.218.86/gil.pyseemto work ?
>
> > >http://87.98.218.86/bench.txt(addedmy apache.conf)
This is what i get in gdb with cflag -g in make file

Starting program: /usr/sbin/apache2 -X
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
[Thread debugging using libthread_db enabled]
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
---Type <return> to continue, or q <return> to quit---
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
[New Thread 0x7f304cb12760 (LWP 6503)]
(no debugging symbols found)
(no debugging symbols found)

It seems that gil.py will work one time and then stops working until
you reloading the WSGI script

William Dode

unread,
Oct 6, 2008, 7:33:04 AM10/6/08
to mod...@googlegroups.com

You have an InterfaceError, then, look also at the log of your database
server...
Did you loose the connection ? Did you share a not thread safe
connection ?

William Dode

unread,
Oct 6, 2008, 10:12:43 AM10/6/08
to mod...@googlegroups.com
On 06-10-2008, William Dode wrote:

...

> The only problem is that there is not a lot of db pool utilities and
> dbutils is one of the most famous...
>

I reported the problem on the dbutils list

gert

unread,
Oct 6, 2008, 4:03:54 PM10/6/08
to modwsgi
081006 21:56:38 InnoDB: Started; log sequence number 0 228604
081006 21:56:38 [Note] /usr/sbin/mysqld: ready for connections.
Version: '5.0.51a-3ubuntu5.1' socket: '/var/run/mysqld/mysqld.sock'
port: 3306 (Ubuntu)

i only see this in mysql error log files ?

gert

unread,
Oct 6, 2008, 5:48:51 PM10/6/08
to modwsgi
Will this share connections between requests ?

import _mysql
db = _mysql.connect('127.0.0.1','root','root','www')

def application(environ, start_response):
db.query("SELECT test FROM test")
row = db.store_result()
v = row.fetch_row()[0][0]
db.close()
response_headers = [('Content-type', 'text/html'),('Content-
Length', str(len(v)))]
start_response('200 OK', response_headers)
return [v]

gert

unread,
Oct 6, 2008, 6:59:08 PM10/6/08
to modwsgi
nope it gives the exact same result, works one time and after the
first request you get
[Tue Oct 07 00:54:22 2008] [error] [client 80.200.212.91] Traceback
(most recent call last):, referer: http://87.98.218.86/
[Tue Oct 07 00:54:22 2008] [error] [client 80.200.212.91] File "/srv/
www/gil.py", line 12, in application, referer: http://87.98.218.86/
[Tue Oct 07 00:54:22 2008] [error] [client 80.200.212.91]
db.query("SELECT test FROM test"), referer: http://87.98.218.86/
[Tue Oct 07 00:54:22 2008] [error] [client 80.200.212.91]
InterfaceError: (0, ''), referer: http://87.98.218.86/

so can you make modwsgi share global variables between requests ?

Graham Dumpleton

unread,
Oct 6, 2008, 9:23:39 PM10/6/08
to mod...@googlegroups.com
2008/10/6 William Dode <wi...@flibuste.net>:
>
> On 04-10-2008, Graham Dumpleton wrote:
>>
>> BTW, if I am right, you would see the behaviour you expect to see if you use:
>>
>> WSGIApplicationGroup %{GLOBAL}
>
> More or less, it give me alternatively two differents local instances...

Sorry, don't understand how that could be at present. What do you get
corresponding to each request when you also output debugging:

print >> sys.stderr, environ.get('mod_wsgi.process_group')
print >> sys.stderr, environ.get('mod_wsgi.application_group')

print >> sys.stderr, environ.get('wsgi.multithread')
print >> sys.stderr, environ.get('wsgi.multiprocess')

print >> sys.stderr, threading.currentThread()

Want to determine if your configuration might still actually be
multithreaded or even multiprocess.

What is the Apache/mod_wsgi configuration you are using? Ie.,
prefork/worker MPM, daemon mode, how many processes/threads.

Graham

Graham Dumpleton

unread,
Oct 6, 2008, 9:28:14 PM10/6/08
to mod...@googlegroups.com
2008/10/6 gert <gert.c...@gmail.com>:

Which says absolutely nothing.

Just because I suggested to someone else that gdb could be used to
debug an issue, doesn't mean it is then a magic bullet that is
applicable to every situation. It will only be of use it quite
specific situations.

I sincerely hope that the debug suggestions you give to people will
not now expand to, 'replace your whole Apache configuration with
yours' and 'run gdb to work out problem'. Both suggestions aren't
helpful. :-)

Graham

William Dode

unread,
Oct 7, 2008, 3:58:09 AM10/7/08
to mod...@googlegroups.com

It is. In your example db will be shared between requests.

But if you have more than one thread you have to know how to share
theses resources ! Is your connection thread safe ?
Don't forget also that if you share the same db connection between
request you cannot use transaction...

You use _mysql instead of mysql and a query on the connection instead of
the cursor... I don't know what you do !

gert

unread,
Oct 7, 2008, 1:27:17 PM10/7/08
to modwsgi
_mysql is a 50% speed increase on what Graham calls the "not again"
benchmark script made by me with has a soul purpose to get the number
of request as high as possible ignoring things like security,
reliability, memory, processing you know the benchmark everybody is
interested in :-)

So clearly my db connections are not made to be used globally and as
always before Graham can say "for god sake why me" i blame Graham for
it.

Your are ride about the START TRANSACTION; not going to work like that
but never the less, I still expect the simple query thing to work and
share the database connection. Note that i use prefork not worker
apache (prefork faster btw using mod_wsgi) So its just memory from a
single process that needs to be available to a other request handled
by the same single threaded process. Unless there is a line in
mode_wsgi that say's if ( group == gert ) { malloc(size_t
i_dont_think_so); } I still think it should work ?

gert

unread,
Oct 7, 2008, 8:33:03 PM10/7/08
to modwsgi
So will start to figure things out but can i ask a global overall
newbie python wsgi question :)

x = 1

def application(environ, start_response):
status = '200 OK'
global x
x = x + 1
output = str(x)
response_headers = [('Content-type', 'text/html'),('Content-
Length', str(len(output)))]
start_response(status, response_headers)
return [output]

if "__main__" == __name__ :
e = ...
r = ...
print application(e,r)

what does e and r need to do some local python testing ?

William Dode

unread,
Oct 8, 2008, 6:56:51 AM10/8/08
to mod...@googlegroups.com
On 07-10-2008, Graham Dumpleton wrote:
>
> 2008/10/6 William Dode <wi...@flibuste.net>:
>>
>> On 04-10-2008, Graham Dumpleton wrote:
>>>
>>> BTW, if I am right, you would see the behaviour you expect to see if you use:
>>>
>>> WSGIApplicationGroup %{GLOBAL}
>>
>> More or less, it give me alternatively two differents local instances...
>
> Sorry, don't understand how that could be at present. What do you get
> corresponding to each request when you also output debugging:

the apache virtualhost conf :
WSGIDaemonProcess blakie.riol user=wilk group=www-user stack-size=524288 python-path=/home/web/wilk/pynclude:/home/web/wilk/blakie.riol/pynclude home=/home/web/wilk threads=1 inactivity-timeout=300 display-name=wsgi-blakie.riol
WSGIProcessGroup blakie.riol
WSGIApplicationGroup %{GLOBAL}
AddHandler wsgi-script .wsgi

the output :

[Wed Oct 08 12:52:47 2008] [error] -- start --
[Wed Oct 08 12:52:47 2008] [error] blakie.riol
[Wed Oct 08 12:52:47 2008] [error]
[Wed Oct 08 12:52:47 2008] [error] False
[Wed Oct 08 12:52:47 2008] [error] False
[Wed Oct 08 12:52:47 2008] [error] <_MainThread(MainThread, started)>
[Wed Oct 08 12:52:47 2008] [error] pid: 12864 id: 3072714848 id.__dict__: 3070588148
[Wed Oct 08 12:52:47 2008] [error] -- start --
[Wed Oct 08 12:52:47 2008] [error] blakie.riol
[Wed Oct 08 12:52:47 2008] [error]
[Wed Oct 08 12:52:47 2008] [error] False
[Wed Oct 08 12:52:47 2008] [error] False
[Wed Oct 08 12:52:47 2008] [error] <_MainThread(MainThread, started)>
[Wed Oct 08 12:52:47 2008] [error] pid: 12864 id: 3072714848 id.__dict__: 3070589644
[Wed Oct 08 12:52:47 2008] [error] -- start --
[Wed Oct 08 12:52:47 2008] [error] blakie.riol
[Wed Oct 08 12:52:47 2008] [error]
[Wed Oct 08 12:52:47 2008] [error] False
[Wed Oct 08 12:52:47 2008] [error] False
[Wed Oct 08 12:52:47 2008] [error] <_MainThread(MainThread, started)>
[Wed Oct 08 12:52:47 2008] [error] pid: 12864 id: 3072714848 id.__dict__: 3070588148
[Wed Oct 08 12:52:47 2008] [error] -- start --
[Wed Oct 08 12:52:47 2008] [error] blakie.riol
[Wed Oct 08 12:52:47 2008] [error]
[Wed Oct 08 12:52:47 2008] [error] False
[Wed Oct 08 12:52:47 2008] [error] False
[Wed Oct 08 12:52:47 2008] [error] <_MainThread(MainThread, started)>
[Wed Oct 08 12:52:47 2008] [error] pid: 12864 id: 3072714848 id.__dict__: 3070589644
[Wed Oct 08 12:53:04 2008] [error] -- start --
[Wed Oct 08 12:53:04 2008] [error] blakie.riol
[Wed Oct 08 12:53:04 2008] [error]
[Wed Oct 08 12:53:04 2008] [error] False
[Wed Oct 08 12:53:04 2008] [error] False
[Wed Oct 08 12:53:04 2008] [error] <_MainThread(MainThread, started)>
[Wed Oct 08 12:53:04 2008] [error] pid: 12864 id: 3072714848 id.__dict__: 3070588148
[Wed Oct 08 12:53:05 2008] [error] -- start --
[Wed Oct 08 12:53:05 2008] [error] blakie.riol
[Wed Oct 08 12:53:05 2008] [error]
[Wed Oct 08 12:53:05 2008] [error] False
[Wed Oct 08 12:53:05 2008] [error] False
[Wed Oct 08 12:53:05 2008] [error] <_MainThread(MainThread, started)>
[Wed Oct 08 12:53:05 2008] [error] pid: 12864 id: 3072714848 id.__dict__: 3070589644

#!/usr/bin/python
import cgi
import threading
import sys
import os

import threading
myloc = threading.local()

def application(environ, start_response):
status = '200 OK'

print >> sys.stderr, '-- start --'


print >> sys.stderr, environ.get('mod_wsgi.process_group')
print >> sys.stderr, environ.get('mod_wsgi.application_group')

print >> sys.stderr, environ.get('wsgi.multithread')
print >> sys.stderr, environ.get('wsgi.multiprocess')

print >> sys.stderr, threading.currentThread()

ch = 'pid: %s id: %s id.__dict__: %s' % (os.getpid(), id(myloc), id(myloc.__dict__))
print >> sys.stderr, ch
output = ch


response_headers = [('Content-type', 'text/html'), ]
start_response(status, response_headers)

return [cgi.escape(output)]


gert

unread,
Oct 8, 2008, 12:40:03 PM10/8/08
to modwsgi
Don't know if this would make any sense but can you try to put global
myloc in the def application ? My simple example did not work without
the global thing

x = 1
def application(environ, start_response):
global x
x = x + 1
output = str(x)
start_response('200 OK', [('Content-type', 'text/html'),('Content-
Length', str(len(output)))])
return [output]

William Dode

unread,
Oct 15, 2008, 7:27:40 AM10/15/08
to mod...@googlegroups.com
On 06-10-2008, William Dode wrote:
>
> On 06-10-2008, William Dode wrote:
>
> ...
>
>> The only problem is that there is not a lot of db pool utilities and
>> dbutils is one of the most famous...
>>
>
> I reported the problem on the dbutils list
>

DBUtils 1.0rc1 now works with mod_wsgi :-)

Reply all
Reply to author
Forward
0 new messages