Your code is perfectly thread safe, yes. But the assignment to sys.stdout IS NOT. There is only one sys.stdout, and all threads use the same one.

Example (two threads):

##Thread 1:
- initializes request from client 1
- sets sys.stdout to StdOut(request ...) object
- writes "hello1 " to sys.stdout
##Thread 2
- initializes request from client 2
- sets sys.stdout to StdOut(request ...) object
- writes "hello2 " to sys.stdout
##Thread 1
- writes "world1" to sys.stdout
- terminates, and sends sys.stdout.buffer to client
##Thread 2
- writes "world2" to sys.stdout
- terminates, and sends sys.stdout.buffer to client

Now look at what will happen with your code and a threading apache:
Client 1 will receive "hello2 world1"
Client 2 will receive "hello2 world1world2"

Explanation:

##Thread 1:
- initializes request from client 1
- sets sys.stdout to StdOut(request ...) object
- writes "hello1 " to sys.stdout
(sys.stdout.buffer == "hello1 ")
##Thread 2
- initializes request from client 2
- sets sys.stdout to StdOut(request ...) object
(and thus replaces the buffer that thread 1 put there, its contents are lost)
- writes "hello2 " to sys.stdout
(sys.stdout.buffer == "hello2 ")
##Thread 1
- writes "world1" to sys.stdout
(sys.stdout.buffer == "hello2 world1")
- terminates, and sends sys.stdout.buffer to client
##Thread 2
- writes "world2" to sys.stdout
(sys.stdout.buffer == "hello2 world1world2")
- terminates, and sends sys.stdout.buffer to client


Mike Looijmans
Philips Natlab / Topic Automation

Fırat KÜÇÜK wrote:
Mike Looijmans yazmış:

Yes,

the problem is not whatever class or method you use to send the output to the client, but the problem is the use of the global sys.stdout variable. The is only one such object in your system. If there are two threads each handling a request, there is no telling to which one the sys.stdout.write or print statement will send its output. To prevent this, you'd have to mutex access to it, and leads to being able to handle only one request at a time.

On many unix flavors, apache defaults to 'forking', which runs each request in a separate process. In these circumstances, you will not detect this problem. On other platforms, or if you modify the httpd.conf file, apache uses threading or even a mix of threading and forking.

Important note: Since print sends to sys.stdout, using print is just as bad a method to send output to the client as sys.stdout.write.

The only solution is to use the context in your handler, i.e.
WRITE("hello world\n")

or the more obvious (like in publisher and PSP):
req.write("Hello world\n")

Anything that makes use of globals to send back data to the client will not work, so "wepi.write" is also out of the question (if wepi is a module).

--
Mike Looijmans
Philips Natlab / Topic Automation


Fırat KÜÇÜK wrote:



import sys
sys.stdout.write(open('penguin.png', 'rb').read())






NO. NO. NO.

sys.stdout is a global variable. If you want sys.stdout.write() to end up in the user's terminal, your web server will be able to either serve only one request at a time, or must be forced into running separate processes for each concurrent request (which will not happen on windows and many other supported platforms).

We made that mistake with cgipython, and we won't make it again. Learn from the mistakes of others, as you do not have the time to make them all yourself.

Mike


Hi,
but i replaced sys.stdout with a StdOut class. is it problem too?

Fırat KÜÇÜK




Hi,


###[StdOut class]###############################################################

class StdOut:
   "replaces sys.stdout"

   buffer = ""

# --------------------------------------------------[overidden methods]-----

   ### [__init__ method]---------------
   def __init__(self, req, headers_object):
       self.req     = req
       self.headers = headers_object

# -----------------------------------------------------[public methods]-----

   ### [write method]---------------
   def write(self, text): self.buffer += str(text)



this is my sys.stdout replacement class and write method use buffer.

and finally after execution of .py file

# send buffer
req.write(sys.stdout.buffer)

I think this is thread safe method for sending data.
print or sys.stdout.write indirectly use req.write method.


# send buffer
req.write(sys.stdout.buffer)



Reply via email to