I am looping a function in python as I created my own constant listener. My question is how can I ensure I don't overflow / crash? Logically this is telling me I am leaving a lot of open functions in the background. Once parameters of my application are met I exit(0) for a clean shut down. but how can I ensure this doesn't eat up memory?
This code works fine btw, but I am simply trying to improve it because it feels really wrong to me that I am calling the function within its self without closing the previous use of it and it just feels dirty. constructive comments please.
e.g. (this is now my actual code)
import serial
import sys
import time
def enterdata():
ser = serial.Serial(sys.argv[1], sys.argv[2])
ser.write("\r")
time.sleep(0.5)
while True:
data = ser.read(ser.inWaiting())
if (len(data) > 0):
a = []
for i in range(len(data)):
a.append(data[i])
if "Please press Enter to activate this console." in "".join(a):
print ("1")
exit(0)
break
ser.close()
enterdata()
ser = serial.Serial(sys.argv[1], sys.argv[2])
ser.write("\r\n")
enterdata()
NEW VERSION SO FAR FROM POSTS MADE:
import serial
import sys
import time
def enterdata():
ser = serial.Serial(sys.argv[1], sys.argv[2])
ser.write("\r")
time.sleep(0.5)
while True:
data = ser.read(ser.inWaiting())
if (len(data) > 0):
a = []
for i in range(len(data)):
a.append(data[i])
if "Please press Enter to activate this console." in "".join(a):
print ('1')
return True
exit(0)
break
ser.close()
ser = serial.Serial(sys.argv[1], sys.argv[2])
ser.write("\r\n")
state = False
while state is not True:
state = enterdata()
This code you showed will give a "RuntimeError: maximum recursion depth exceeded" Error because of Python sets a default value for how many recursions can occur in one function at a time.
Any yours is infinite and definitely will cause problems even if you change this default limit.
Why not make a loop yourself and call the function at will ?
found = False
while not found:
extracted_data = lookfordata()
if extracted_data == "I want it to be equal to this":
found = True
I see you edited the post. Whatever you are trying to do, that method is not efficent, not recommended and not pretty. All the good reasons not to use it.
Imagine that you will handle some data larger than you are using now, you won't know if the recursion stopping condition will come to pass before you exceed the limit. It's also no use to increase limit all the time you encounter a bigger data. I think it should be any programmer's goal to avoid repetition and coming up with programs that can handle any type of unexpected input.
You updated your post again. This way of input handling is much better than raw recursion. Just to mention, instead of;
for i in range(len(data)):
a.append(data[i])
use
for i in data:
a.append(i)
Related
UPDATE: I found the source of the program hanging. In my pdthread it calls mysocket1.sendall(mydata). It doesn't seem to be able to get past this. Does anyone know why this might be an issue?
I have the following code:
mysocket1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
mysocket1.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
mysocket1.connect(('127.0.0.1', 10001))
while mysocket1:
try:
msg = mysocket1.recv(4092)
msg = pickle.loads(msg)
print(msg)
for pd in pd_objects:
if msg[0] == pd.cam_ip and str(msg[1]) == 'ON' and pd.pd_active == False:
pd.pd_active = True
pdthread = Thread(target=get_pd_data(pd.cam_ip))
pdthread.daemon = True
pdthread.start()
print("testing1")
elif msg[0] == pd.cam_ip and msg[1] == 'OFF':
pd.pd_active = False
print("testing else")
print("testing2")
except:
traceback.print_exc(file=sys.stdout)
break
print("reached end")
I have another python program connected on the other end. This connects and runs perfectly the first time I press a button to activate it. I have my data sending over in the pdthread and all works swell. It's what happens afterwards that's the problem. Future button presses are NOT picked up by this side. The data is being sent over the socket just fine from the other end, it's just not being received here.
I've put in some prints for testing and I found a few interesting things that I cannot explain which is why I'm asking here:
The print("testing1") is never printed. Ever. Not even after the first successful click. Which makes me think that pdthread.start() is behaving like pdthread.join()... which confuses me.
The print("testing else") is never printed. This is expected given my testing but I wanted to rule it out.
Here's the weirdest one. I have two items in my pd_objects list. When I click the button that sends the pd.cam_ip of the first item, print("testing2") does not print, but it DOES print if I click the one for the second item in the list.
Can anyone help explain this bizarre behaviour?
EDIT: the final print is also never printed
I use the following piece of code to read the serial port until i get a terminating character.
"""Read until you see a terminating character with a timeout"""
response=[]
byte_read=''
break_yes=0
time_now = time.clock()
while ((not (byte_read=='\r') ) and (break_yes==0)):
byte_read = self.ser.read(1)
if (not(len(byte_read)== 0) and (not (byte_read =='\r'))):
response.append(byte_read)
if ( time.clock() - time_now > 1 ):
if self.DEBUG_FLAG:
print "[animatics Motor class] time out occured. check code"
break_yes=1
if break_yes==0:
return ''.join(response)
else:
return 'FAIL'
This works well but because of the while loop, the cpu resources are taken up.
I think that having a blocking read(1) with a timeout will save some of the cpu.
The flag i am looking for C is "MIN == 0, TIME > 0 (read with timeout)" in termios
i am looking for a similar flag in Python.
I could also use the io.readline to read till i get '\r', but i want to stick to pyserial as much as possible without any other dependency.
Would greatly appreciate advice. Do let me know if i should do it in a completely different way either too.
Thanks,
You should read the documentation of Pyserial: it clearly states that a timeout of 0 as you pass it to the constructor will turn on non-blocking behaviour:
http://pyserial.sourceforge.net/pyserial_api.html#classes
Just get rid of the timeout parameter, and you should be set.
Aight, so I found out a way. Instead of polling with the no timeout, I use the select module in python, which is similar to the one in C.
It returns if any data is available immediately, or waits for the timeout period and exits, which is precisely what i wanted. I took deets comments for cleaning up the code and it looks like so now.
def readOnly(self):
"""Read until you see a terminating character with a timeout"""
response=[]
byte_read=''
while (not (byte_read=='\r')):
reading,_,_ = select.select([self.ser], [], [], 1) #returns immediately if there is data on serial port. waits 1 second to timeout if not.
if reading !=[]: #something is to be read on the file descriptor
byte_read = self.ser.read(1)
if (byte_read !='\r'):
response.append(byte_read)
else: #'\r' received
return ''.join(response)
break
else:
if self.DEBUG_FLAG:
print "[Motor class] time out occured. check code"
return 'FAIL'
break
`
This decreased the cpu usage from 50% to 5% so life is better now.
Thanks,
Basically, I want my throw raw input variable to be skipped so that it can still be accessed and referred to later on, but doesn't need a user input to continue, so what happens is if you type "throw brick" within 5 seconds, it will bring you to the outcome print "good job!"
throw = raw_input()
throw_command = ["throw brick"]
import time
me.sleep(5)
if throw in throw_command:
print "good job!"
if throw not in throw_command:
print "GAME OVER"
restart
I know such thing as a goto or jump don't exist in such a structure-based code. So, if anyone could happen to provide an alternative, your assistance would be much appreciated.
I'm not sure I understand what you're trying to do, but it sounds to me like this:
Ask the user for input, but timeout after 5 seconds (your time.sleep(5))
Repeat over and over again (your restart)
If so, it looks like this would be one way to do it: Keyboard input with timeout in Python
I modified the select-based answer with the details of your code:
import sys
import select
throw_command = ["throw brick"]
while True:
print "\nEnter command:"
i, o, e = select.select( [sys.stdin], [], [], 5 ) # times out after 5 seconds
if i: # If input was provided
throw = sys.stdin.readline().strip()
if throw in throw_command:
print "good job!"
break
else:
print "GAME OVER"
else:
print "You didn't enter anything!"
The use of select is a little advanced (ideally, raw_input should have an optional timeout argument) but it's easier than using threads which is the only way I could think of doing this with raw_input.
The use of a while loop instead of your restart attempt at a go-to should be self-explanatory.
I do believe that thread may accomplish this, although I am not sure. Most of the threads out there that address this problem doesn't address it to match my problem. I have created a simple mud-like fighting system that executes when you 'fight' an NPC. I have the code that runs under a while loop that checks health between you and NPC and if one of you dies then the loop ends.
However
During the loop I want to have it where a user can type in commands, instead of being stuck watching a looping code block without you being able to do anything. From what I have read online it looks like thread module may be of some help to me? Also if anyone has PyGame experience, maybe looking into that would be a solution? Please let me know what you think.
Below is a very simple example of what I am trying to accomplish.
import time
fighting = True
while fighting:
# do the magic here
time.sleep(4) # to give it a nice even pace between loop intervals
Although at any time i want to be able do input a command like a skill or spell.
Any ideas or suggestions?
You can separate your human interface and fight game into separate threads. The fight game uses a queue for input, which uses a timeout to continue. Here is a very simple queue structure that should minimally do what you want.
import time
import threading
import Queue
def fighter(input_queue):
while True:
start = time.time()
# do stuff
wait = time.time() - start()
if wait <= 0.0:
wait = 0
try:
msg = input_queue.get(wait, wait)
if msg == 'done':
return
# do something else with message
except Queue.Empty:
pass
def main():
input_queue = Queue.Queue()
fight_thread = threading.Thread(target=fighter, args=(input_queue,))
fight_thread.start()
while True:
msg = raw_input('hello ') # py 2.x
input_queue.put(msg)
if msg == 'done':
break
fight_thread.join()
If you only want this to work on Windows, and you want to keep your simple event loop:
fighting = True
inputbuf = ''
while fighting:
# do the magic here
while msvcrt.khbit():
newkey = msvcrt.getwche()
inputbuf += newkey
if newkey == '\r':
process_command(inputbuf)
inputbuf = ''
time.sleep(4) # to give it a nice even pace between loop intervals
On the other hand, if you want to use a background thread, it would be a lot simpler:
def background():
for line in sys.stdin:
process_command(line)
bt = threading.Thread(target=background)
bt.start
fighting = True
while fighting:
# do the magic here
time.sleep(4) # to give it a nice even pace between loop intervals
This works cross-platform, and it gives normal line-buffered input (including full readline support), which people will probably like.
However, I'm assuming you want that process_command to share information with the # do the magic here code, and possibly even to set fighting = False. If you do that without any thread synchronization, it will no longer work cross-platform. (It may work on both Windows CPython and Unix CPython, but will probably not work on IronPython or Jython—or, worse, it will work most of the time but randomly fail just often enough that you have to fix it but not often enough that you can debug it…)
What you may be looking for is a non-blocking raw_input implementation. This would allow the loop to keep going while allowing the user a possibility at entering commands.
There is an example of an implementation of this here and here. Maybe you can adapt one of them to suit your purpose.
Edit:
Or, if you're working on Windows...
I have a 'while' loop in my Python app (v2.7) which basically communicates with a Bluetooth GPS device and the loop continues for as long as there is data being received. In essence, the while loop looks like this:-
> data = ""
>
> if data == None:
> print "Connection Failed" else:
> print "Connection Established"
>
> while True:
> data = socket.recv(1024)
Now what I want to do is leave this while loop running continually throughout the life of the program until the bluetooth device is switched off which in turn will end the loop as no data will be being received. Nonetheless, as this while loop continues, I then want to move onto another method which will parse the data.
How can I leave the loop running and move on to the next command? Is threading required? I'm new to the concept of threading and so please be patient with me :)
Thanks
Yeah, because you're essentially going to be doing two things at the same time, you'll have to create a new thread (using threading) or perhaps more simply a new process (using multiprocessing or just os.fork)
The easiest thing to do is to put this part in a function, and use multiprocessing or threading to start the function in a different process. Typically you'll have less weirdness with multiple processes than multiple threads, just FYI.
received = ""
while True:
data = socket.recv(1024)
if not data:
break # ends the while loop
received+=data
do_stuff(received)