clicker eats a lot of processor time - python 3 - python

I have a simple program that does the following:
1) User points a mouse somewhere,
2) then user presses Space,
3) and computer does certain amount of left-botton-mouse-clicks at that point.
The program works fine, there is only one problem - it eats 30-50% of processor time on a 4-core processor. Where is the problem?
import pyautogui
import ctypes
pyautogui.FAILSAFE = True
def get_space_state():
hllDll = ctypes.WinDLL ("User32.dll")
VK_SPACE = 0x20
return hllDll.GetKeyState(VK_SPACE)
while True:
if get_space_state() == -127 or get_space_state() == -128:
print ("yes")
pyautogui.click(clicks=40 , interval=0.01)
Thanks a lot.

Correct answer: I suspect a constant polling because of while True:. Insert sleep or pyautogui.PAUSE there (inside while loop, before if), if process sleeps for a while (even less then a second) it frees a lot of CPU cycles
Minor optimizations:
Also you're initializing entire User32.dll in every loop... twice (because of or), it seems.
And User32 is HUGE
Hints and notes:
If I remember python rules right, you just can move hllDll to a module level (above function defintion), get_space_state() will find it anyway. Or you can pass it as a parameter. And you don't need to redefine VK_SPACE every function call - though this is a micro-optimization
If all these fixes won't work, you should use debuggers, to find a true source of slowdowns
If you happen to have problems like this in the future, use something like Immunity or WinDbg to attach to process and see what's going on there

Related

Duration calculation and control in ROS - furthermore why does this script keep running even after pressing Ctrl-C?

I have written some code to make the turtlebot turn around. The code is working. What I want to know is how fast the turtlebot is running and how I can control it. Forexample, how can I ensure that the turtlebot turns 5 degrees in one minute?
Last part of the question. After pressing Ctrl-C, the turtlebot stops but the script keeps running. Why? and how can I stop that?
this post does not really help.
went through this post .Does that mean that the while loop below runs 5 times a second regardless of the values I put in the for loops? Or does it mean ROS tries its best to make sure that the loop runs 5 times a second to the best of my machine's ability?
Thank you very much.
# 5 HZ
angle = 5
r = rospy.Rate(5);
while not rospy.is_shutdown():
# code to turn
for x in range(0,100):
rospy.loginfo("turn")
turn_cmd.angular.z = radians(angle)
new_angle = (angle + new_angle) % 360
self.cmd_vel.publish(turn_cmd)
r.sleep()
# code to pause
for x in range(0,100):
rospy.loginfo("stop")
turn_cmd.angular.z = radians(0)
self.cmd_vel.publish(turn_cmd)
r.sleep()
def shutdown(self):
# stop turtlebot
rospy.loginfo("Stop turning")
self.cmd_vel.publish(Twist())
rospy.sleep(1)
According to ROS Wiki, the rospy.Rate convenience class makes a best effort to maintain the loop running at the specified frequency by considering the execution time of the loop since the last successful r.sleep(). This means in your case: as long as the code execution time within the loop does not exceed 1/5 seconds, rospy.Rate will make sure the loop runs at 5Hz.
Regarding the script not stopping when pressing Ctrl-C:
KeyboardInterrupt will be handled differently than in normal Python scripts when using rospy.
rospy catches the KeyboardInterrupt signal to set the rospy.is_shutdown() flag to true. This flag is only checked at the end of each loop, therefore if pressing Ctrl-C during the for-loop executions, the script cannot be stopped because the flag is not checked immediately.
A manual way to signal a shutdown of the node is to use rospy.signal_shutdown(). For this, the disable_signals option needs to be set to true when initializing the ROS node (see Section 2.3 here). Note that you will additionally have to manually invoke the correct shutdown routines to ensure a proper cleanup.

Question with python, music and events, is there a more elegant way of programming this?

Goal: To create a program that will be able to turn off and on lights to music based on events that are triggered from midi notes.
Hello all, I am hoping that this isn't too broad of a question to ask. I am working on a project where I get events from a midi file and turn those events into time. I take a note from the midi file and append it to a list as the time it was placed
Example:
https://imgur.com/swZsrk9
I take all of those and place them into a list. Don't worry about how I do that as that is not my main goal to discuss. I've just substituted the list with a hard-coded one on my example code.
I now have a list of times that I want lights to either turn on or off, now I just need to set an infinite loop with a timer that starts at 0 seconds (with the start of the song) and when the timer == (the next time in the list) it will print out a line. Here is my code:
import socket
import sys
import random
import time
from pygame import mixer
from mido import MidiFile
masterList = [12.37, 14.37, 15.12, 15.62,16.36, 17.61, 18.11, 19.11, 19.61, 20.35,]
mixer.init()
song = mixer.Sound('song.wav')
startTime = time.time()
endTime = startTime + song.get_length()
print(masterList)
print('Starting song.')
song.play()
print('Playing song, timer:',startTime)
while time.time() <= endTime:
#print(round(time.clock(),1),masterList[0])
if round(time.clock(),2) == masterList[0]:
print(round(time.clock(),2),"<-",masterList[0],"------------------")
del masterList[0]
#print('playing...')
time.sleep(.01)
mixer.quit()
Here is a video of it runing:
https://www.youtube.com/watch?v=VW-eNoJH2Wo&feature=youtu.be
Ignore the deprecation warnings
It works but sometimes, due to the nature of programming, the time.clock() does not always == the next item in the list. I knew that this would be a problem going in as you can't rely on how long the code takes to execute. Sometimes it takes a few more milliseconds than usual to complete a while loop so then when you call the time.clock() method it != the next time in the list. Then the list does not remove it's first item and then it will never equal that first item.
I tried going by 10 milliseconds (.1) but it doesn't give me the accuracy I need.
Also, it seems clunky, sometimes the events are delayed a few milliseconds and it makes the effect not as pleasing. As you can see from my video the times of the prints aren't lined up completely where they need to be, even though they are perfectly placed on where they need to be in the midi file.
Question: Is there a more elegant way of tackling this? I seem to keep finding ways of patching it to work better and then it always goes back to the nature of programming, where the cpu always is unreliable. I've been trying to think of different ways of doing this but I can't come up with any. Your help would be much appreciated!!
Since you're deleting the notes as you play them, have you tried using >= instead of ==?
E.g.,:
while time.time() <= endTime:
#print(round(time.clock(),1),masterList[0])
if round(time.clock(),2) >= masterList[0]:
print(round(time.clock(),2),"<-",masterList[0],"------------------")
del masterList[0]
That way the note will play as soon as possible after the specified time, and remove it from the queue. Only way to know actual performance is to test it, but at the very least it won't skip notes.

Add time delay between every statement of python code

Is there an easy way to execute time delay (like time.sleep(3)) between every statement of Python code without having to explicitly write between every statement?
Like in the below Python Script which performs certain action on SAP GUI window. Sometimes, the script continues to the next statement before the previous statement is complete. So, I had to add a time delay between every statement so that it executes correctly. It is working with time delay, but I end up adding time.sleep(3) between every line. Just wondering if there is a better way?
import win32com.client
import time
sapgui = win32com.client.GetObject("SAPGUI").GetScriptingEngine
session = sapgui.FindById("ses[0]")
def add_record(employee_num, start_date, comp_code):
try:
time.sleep(3)
session.findById("wnd[0]/tbar[0]/okcd").text = "/npa40"
time.sleep(3)
session.findById("wnd[0]").sendVKey(0)
time.sleep(3)
session.findById("wnd[0]/usr/ctxtRP50G-PERNR").text = employee_num
time.sleep(3)
session.findById("wnd[0]").sendVKey(0)
time.sleep(3)
session.findById("wnd[0]/usr/ctxtRP50G-EINDA").text = start_date
time.sleep(3)
session.findById("wnd[0]/usr/tblSAPMP50ATC_MENU_EVENT/ctxtRP50G-WERKS[1,0]").text = comp_code
time.sleep(3)
session.findById("wnd[0]/usr/tblSAPMP50ATC_MENU_EVENT/ctxtRP50G-PERSG[2,0]").text = "1"
time.sleep(3)
session.findById("wnd[0]/usr/tblSAPMP50ATC_MENU_EVENT/ctxtRP50G-PERSK[3,0]").text = "U1"
time.sleep(3)
session.findById("wnd[0]/usr/tblSAPMP50ATC_MENU_EVENT").getAbsoluteRow(0).selected = True
time.sleep(3)
return "Pass"
except:
return "failed"
The right way to do what you asked for is almost certainly to use the debugger, pdb.
The right way to do what you want is probably something completely different: find some signal that tells you that the step is done, and wait for that signal. With problems like this, almost any time you pick will be way, way too long 99% of the time, but still too short 1% of the time. That signal may be joining a thread, or waiting on a (threading or multiprocessing) Condition, or getting from a queue, or awaiting a coroutine or future, or setting the sync flag on an AppleEvent, or… It really depends on what you're doing.
But if you really want to do this, you can use settrace:
def sleeper(frame, event, arg):
if event == 'line':
time.sleep(2)
return sleeper
sys.settrace(sleeper)
One small problem is that the notion of line used by the interpreter may well not be what you want. Briefly, a 'line' trace event is triggered whenever the ceval loop jumps to a different lnotab entry (see lnotab_notes.txt in the source to understand what that means—and you'll probably need at least a passing understanding of how bytecode is interpreted, at least from reading over the dis docs, to understand that). So, for example, a multiline expression is a single line; the line of a with statement may appear twice, etc.1
And there's probably an even bigger problem.
Sometimes, the script continues to next step before the previous step is fully complete.
I don't know what those steps are, but if you put the whole thread to sleep for 2 seconds, there's a good chance the step you're waiting for won't make any progress, because the thread is asleep. (For example, you're not looping through any async or GUI event loops, because you're doing nothing at all.) If so, then after 2 seconds, it'll still be just as incomplete as it was before, and you'll have wasted 2 seconds for nothing.
1. If your notion of "line" is closer to what's described in the reference docs on lexing and parsing Python, you could create an import hook that walks the AST and adds an expression statement with a Call to time.sleep(2) after each list element in each body with a module, definition, or compound statement (and then compiles and execs the result as usual).
Anything you want to happen in a program has to be explicitly stated - this is the nature of programming. This is like asking if you can print hello world without calling print("hello world").
I think the best advice to give you here is: don't think in terms of "lines", but think in term of functions.
use debugging mode and watch each and every line executing line by line.

Python Curses: Exiting a program fast

What is the best way to quickly exit a Python program with an infinite loop that uses curses module?
I've tried adding nodelay() method coupled with this at the end of the loop:
if screen.getch() == ord('q'):
break
However, it takes 2-3 seconds to make all the function calls on one iteration of the loop. And because of the application, it doesn't make sense to run the loop more often than every 5 second. This means that in order for my way of exiting the program to work, I sometimes have to press and hold 'q' for 2-8 seconds.
My code looks like this:
import curses
import time
def main(screen):
refresh_rate = 5
screen.nodelay(1)
# Infinite loop. Displays information and updates it
# every (refresh_rate) # of seconds
while True:
# Makes several http requests
# and passes responses through multiple functions
# Escape infinite loop
if screen.getch() == ord('q'):
break
# Wait before going through the loop again
time.sleep(refresh_rate)
if __name__ == "__main__":
curses.wrapper(main)
My other solution was to replace while True with:
loop = 1
while loop:
#Loop code
if screen.getch() == ord('q'):
loop = -1
This way, there is no need to press and hold 'q' to exit the program. But it can still take up to 8 seconds to exit after pressing 'q' once.
For obvious reasons, this doesn't seem to be the best way of exiting the program. I am pretty sure there should be a better (faster) solution.
Other than that, the program works fine. It's 2 files with more than 300 lines, so I am posting just the relevant parts of the code with my attempted solutions.
Given that you have nodelay already, the usual approach is to use napms with a small (20-50 milliseconds) time, and addressing your 5-seconds goal, to run the functions after several (10-25) repetitions of the getch/napms loop.
Mixing curses and standard I/O doesn't really work well unless you take care to flush things when switching between the two.
What's probably happening is that your 'q' is coming in between the getch() and the sleep calls. Given that getch() takes a fraction of a second to execute and sleep locks the program for 5 seconds, it's very likely that any time you press a key you're going to wait.
The easiest way to exit any python script is to press Ctrl-C - it spawns a KeyBoardInterrupt exception that can be handled like:
try:
while True:
do_something()
except KeyboardInterrupt:
pass
Granted, if this is meant to be a user-facing application, that might not be sufficient. But it's also unlikely that any production application would operate without a full event loop and a UI that would allow them to exit.
Last, if you want another way of doing what you're already doing, you can use:
import sys
sys.stdin.read(1)
To read 1 bye of user input at a time. I'd go for the Ctrl-C route, if I were you.

Python 2.X / Tkinter needs print to run

Firstly, very much Py Newby!
I have written a program to import data from a file and display it as an image using tkinter. The loop that is misbehaving runs thus:
Get data and plot
for x in xrange(WIDE):
for y in xrange(HIGH):
dataPointLo = inFile.read(1)
dataPointHi = inFile.read(1)
pixelValue = ((ord(dataPointLo) + 256*(ord(dataPointHi)))-31500)
colour = rgb[pixelValue]
#print below makes prog run!
print pixelValue
img.put(colour, to=(x,y))
As suggested by the comment, leaving out the print stops it working, but it locks one core of the processor at 100% for as long as you leave it (well at least 20 mins!). This effect occurs both in IDLE and from the command line (Ubuntu 12.04). Of course, the print to the IDLE window slows the program down, so I would like to remove it! Any thoughts?
it sounds like the process you are running takes a long time to complete, i would suggest that the reason you think it stops is because the window doesn't update while the process is busy unless you tell it to. i suggest you add a function like the following to your code and call it once before you enter your loop:
def keep_alive(self):
self.update()
self.after(100, self.keep_alive)
this way you are adding an event to update the window every 100ms(ish) to the event loop, which will keep the program responsive. you can adjust the timing to suit you, too often will slow your loop down, too far apart and the program will feel sluggish.

Categories

Resources