Reputation: 25
My code accepts gps data from multiple sources aggregates it and sends it back out to multiple clients connected to a threaded single socket. I got it working but the output threads seem to run off with cpu resources.
if I add code to wait for some data from the client the cpu use disappears but the clients only accept a stream of gps info they don't send anything.
Below is the server code that sends data ok but runs high CPU
class ThreadedServerRequestHandler(SocketServer.StreamRequestHandler):
def handle(self):
global SendData
global SendNow
while True:
SendNow
for line in SendData:
self.request.sendall(line)
SendData = []
SendNow = False
return
class ServerThread(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
daemon_threads = True
allow_reuse_address = True
if __name__ == '__main__':
import socket
import threading
address = TxServer
server = ServerThread(address, ThreadedServerRequestHandler)
t = threading.Thread(target=server.serve_forever)
t.setDaemon(True) # don't hang on exit
t.start()
if I change it to below cpu stops but it only outputs data if I send a keystroke.
class ThreadedServerRequestHandler(SocketServer.StreamRequestHandler):
def handle(self):
global SendData
global SendNow
while True:
self.data = self.request.recv(1024).strip()
if self.data == '':
print 'closing thread'
break
while SendNow == True:
for line in SendData:
self.request.sendall(line)
SendData = []
SendNow = False
return
Is there any way to pause the thread until data is sent? or can I simulate a received message to trigger a data burst from the main program?
Upvotes: 1
Views: 2508
Reputation: 365707
The reason it's using 100% CPU is that when you have nothing to write, you just keep spinning as fast as you can until there is something to write:
while True:
SendNow
for line in SendData:
self.request.sendall(line)
SendData = []
SendNow = False
To make it not use 100% CPU, you have to find something for it to wait on.
Your fix does this by waiting on received data, but since you don't normally have any data to receive, this isn't very useful. (As you put it, "it only outputs data if I send a keystroke".)
Meanwhile:
Is there any way to pause the thread until data is sent?
Sure. And you're already doing it. That's what sendall
does. But that doesn't help. The problem is that once you've sent all of the data, you go back through the loop over and over until there's more data to send.
or can I simulate a received message to trigger a data burst from the main program?
Of course, but what would you use to trigger that simulated receive? If you're just going to spin simulating receives as fast as possible, that won't help anything.
I think what you want here is a condition variable around the data. Something like this:
SendCondition = threading.Condition()
class ThreadedServerRequestHandler(SocketServer.StreamRequestHandler):
def handle(self):
global SendCondition
global SendData
while True:
with SendCondition:
while not SendData:
SendCondition.wait()
for line in SendData:
self.request.sendall(line)
SendData = []
Then, whatever your code is that sets SendData
(which you didn't show) looks something like this:
global SendCondition
global SendData
# ...
new_send_data = <whatever>
with SendCondition:
SendData.append(new_send_data)
SendCondition.notify()
Upvotes: 3