Mike Looijmans yazmış:
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)
Hi,
Yes i understood. so we should use an alias or directly req.write for it.
or print operator have to overload.
thanks.