import time
import random
def timer():
correct = 1
x = 0
while correct != 2:
time.sleep(0.1)
x = x + 0.1
def round1():
numb = random.randint(1, 100)
print(numb)
timer()
ans = input(">")
if ans == numb:
correct = 2
x = round(x)
print("you did that in", x ,"seconds!")
round1()
I was trying to get both functions to run together (have the game playing and the timer going in the background) but as soon as the timer started it would let me continue the game.
In the given program, I have created two different functions that will work at the same time. I have used threading to create thread of functions and sleep to limit the printing speed. In similar manner you can use game and timer function together.
from threading import Thread
from time import sleep
#sleep is used in functions to delay the print
#the below functions has infinite loop that will run together
#defining functions
def func1():
for x in range(20):
sleep(1)
print("This is function 1.")
def func2():
for x in range(10):
sleep(2)
print("This is function 2.")
#creating thread
thread1=Thread(target=func1)
thread2=Thread(target=func2)
#running thread
thread1.start()
thread2.start()
Related
I am trying out multiprocessing for my Monty Hall game simulation for improved performance. The game is payed 10mm times and takes ~17 seconds when directly run, however, my multiprocessing implementation is taking significantly longer to run. I am clearly doing something wrong but I can't figure out what.
import multiprocessing
from MontyHall.game import Game
from MontyHall.player import Player
from Timer.timer import Timer
def doWork(input, output):
while True:
try:
f = input.get(timeout=1)
res = f()
output.put(res)
except:
break
def main():
# game setup
player_1 = Player(True) # always switch strategy
game_1 = Game(player_1)
input_queue = multiprocessing.Queue()
output_queue = multiprocessing.Queue()
# total simulations
for i in range(10000000):
input_queue.put(game_1.play_game)
with Timer('timer') as t:
# initialize 5 child processes
processes = []
for i in range(5):
p = multiprocessing.Process(target=doWork, args=(input_queue, output_queue))
processes.append(p)
p.start()
# terminate the processes
for p in processes:
p.join()
results = []
while len(results) != 10000000:
r = output_queue.get()
results.append(r)
win = results.count(True) / len(results)
loss = results.count(False) / len(results)
print(len(results))
print(win)
print(loss)
if __name__ == '__main__':
main()
This is my first post. Advice on posting etiquette is also appreciated. Thank you.
Code for the Classes:
class Player(object):
def __init__(self, switch_door=False):
self._switch_door = switch_door
#property
def switch_door(self):
return self._switch_door
#switch_door.setter
def switch_door(self, iswitch):
self._switch_door = iswitch
def choose_door(self):
return random.randint(0, 2)
class Game(object):
def __init__(self, player):
self.player = player
def non_prize_door(self, door_with_prize, player_choice):
"""Returns a door that doesn't contain the prize and that isn't the players original choice"""
x = 1
while x == door_with_prize or x == player_choice:
x = (x + 1) % 3 # assuming there are only 3 doors. Can be modified for more doors
return x
def switch_function(self, open_door, player_choice):
"""Returns the door that isn't the original player choice and isn't the opened door """
x = 1
while x == open_door or x == player_choice:
x = (x + 1) % 3 # assuming there are only 3 doors. Can be modified for more doors
return x
def play_game(self):
"""Game Logic"""
# randomly places the prize behind one of the three doors
door_with_prize = random.randint(0, 2)
# player chooses a door
player_choice = self.player.choose_door()
# host opens a door that doesn't contain the prize
open_door = self.non_prize_door(door_with_prize, player_choice)
# final player choice
if self.player.switch_door:
player_choice = self.switch_function(open_door, player_choice)
# Result
return player_choice == door_with_prize
Code for running it without multiprocessing:
from MontyHall.game import Game
from MontyHall.player import Player
from Timer.timer import Timer
def main():
# Setting up the game
player_2 = Player(True) # always switch
game_1 = Game(player_2)
# Testing out the hypothesis
with Timer('timer_1') as t:
results = []
for i in range(10000000):
results.append(game_1.play_game())
win = results.count(True) / len(results)
loss = results.count(False) / len(results)
print(
f'When switch strategy is {player_2.switch_door}, the win rate is {win:.2%} and the loss rate is {loss:.2%}')
if __name__ == '__main__':
main()
As you did not give the full code that we can run locally, I can only speculate. My guess is that you are passing an object(a method from your game) to other processes so pickling and unpickling took too much time. Unlike multithreading where you can "share" data, in multiprocessing, you need to pack the data and send to the other process.
However, there's a rule I always follow when I try to optimize my code - profile before optimizing! It would be much better to KNOW what's slow than GUESS.
It's a multiprocessing program so there are not a lot of options in the market. You could try viztracer which supports multiprocessing.
pip install viztracer
viztracer --log_multiprocess your_program.py
It will generate a result.html that you can open with chrome. Or you can just do
vizviewer result.html
I would suggest to reduce the iteration number so you can have a view of the whole picture(because viztracer uses a circular buffer and 10 million iterations will definitely overflow). But, you can still get the last piece of your code executing if you don't, which should be helpful enough for you to figure out what's going on.
I used viztracer as you gave the whole code.
This is one of your iteration in your worker process. As you can tell, the actual working part is very small(the yellow-ish slice in the middle p...). Most of the time has been spent on receiving and putting data, which eliminates the advantage of parallelization.
The correct way to do this is do it in batches. Also as this game does not actually require any data, you should just sent "I want to do it 1000 times" to the process, and let it do it, instead of sending the method one by one.
There's another interesting problem that you can easily find with viztracer:
This is the big picture of your worker process. Notice the large "nothing" in the end? Because your worker needs a timeout to finish, and that's when they are waiting. You should come up with a better idea to elegantly finish your worker process.
Updated my code. I fundamentally misunderstood the multiprocessing method.
def do_work(input, output):
"""Generic function that takes an input function and argument and runs it"""
while True:
try:
f, args = input.get(timeout=1)
results = f(*args)
output.put(results)
except:
output.put('Done')
break
def run_sim(game, num_sim):
"""Runs the game the given number of times"""
res = []
for i in range(num_sim):
res.append(game.play_game())
return res
def main():
input_queue = multiprocessing.Queue()
output_queue = multiprocessing.Queue()
g = Game(Player(False)) # set up game and player
num_sim = 2000000
for i in range(5):
input_queue.put((run_sim, (g, num_sim))) # run sim with game object and number of simulations passed into
# the queue
with Timer('Monty Hall Timer: ') as t:
processes = [] # list to save processes
for i in range(5):
p = multiprocessing.Process(target=do_work, args=(input_queue, output_queue))
processes.append(p)
p.start()
results = []
while True:
r = output_queue.get()
if r != 'Done':
results.append(r)
else:
break
# terminate processes
for p in processes:
p.terminate()
# combining the five returned list
flat_list = [item for sublist in results for item in sublist]
print(len(flat_list))
print(len(results))
I have been trying to make a reaction timer for a project to test reaction times. It uses 'perf_counter' to record the times before and after an input to test how long it takes to press the enter key. The issue is that the enter key can be spammed which makes it seem if they have a reaction time of 0.000001 seconds. I have made a class which disables the keyboard and enables it when I want. Even in that case, people are able to sneak in extra enter presses between the disables and enables. I have attached the code below. Any ideas how to prevent enter spamming?
import time, random, msvcrt
from math import log10, floor
def round_sig(x, sig=5):
return round(x, sig-int(floor(log10(abs(x))))-1)
class keyboardDisable():
def start(self):
self.on = True
def stop(self):
self.on = False
def __call__(self):
while self.on:
msvcrt.getwch()
def __init__(self):
self.on = False
import msvcrt
disable = keyboardDisable()
disable.start()
print('When I say __GO__ you hit ENTER! This will happen 3 times. Got it?')
time.sleep(2)
print('Ready')
time.sleep(1)
print('Steady')
time.sleep(random.randint(2,5))
print('#####__GO__######')
disable.stop()
tic = time.perf_counter()
a = input()
toc = time.perf_counter()
if msvcrt.kbhit():
disable.start()
timeSpent = toc-tic
print('Your first time was '+str(timeSpent) + ' seconds')
time.sleep(1)
print('The next one is coming up.')
time.sleep(1)
print('Ready')
time.sleep(1)
print('Steady')
time.sleep(random.randint(2,5))
print('#####__GO__######')
disable.stop()
tic2 = time.perf_counter()
b = input()
toc2 = time.perf_counter()
if msvcrt.kbhit():
disable.start()
timeSpent2 = toc2-tic2
print('Your second time was '+str(timeSpent2) + ' seconds')
time.sleep(1)
print('The last one is coming up.')
time.sleep(1)
print('Ready')
time.sleep(1)
print('Steady')
time.sleep(random.randint(2,5))
print('#####__GO__######')
disable.stop()
tic3 = time.perf_counter()
c = input()
toc3 = time.perf_counter()
timeSpent3 = toc3-tic3
print('Your last time was '+str(timeSpent3) + ' seconds')
average = (timeSpent + timeSpent2 + timeSpent3)/3
numAverage = round_sig(average)
print('Your average time is '+str(numAverage) + ' seconds')
The keyboard-disabling code never really runs.
Here's a simplification of your program that uses a function to capture one reaction time and calls it thrice.
The clear_keyboard_buffer() function (that should consume all outstanding keystrokes) was borrowed from https://stackoverflow.com/a/2521054/51685 .
import time, random, msvcrt, math
def round_sig(x, sig=5):
return round(x, sig - int(math.floor(math.log10(abs(x)))) - 1)
def clear_keyboard_buffer():
while msvcrt.kbhit():
msvcrt.getwch()
def get_reaction_time():
print("Ready")
time.sleep(1)
print("Steady")
time.sleep(random.randint(2, 5))
print("#####__GO__######")
clear_keyboard_buffer()
tic = time.perf_counter()
a = input()
toc = time.perf_counter()
return toc - tic
print("When I say __GO__ you hit ENTER! This will happen 3 times. Got it?")
time1 = get_reaction_time()
print(f"Your first time was {time1} seconds")
time.sleep(1)
print("The next one is coming up.")
time2 = get_reaction_time()
print(f"Your first time was {time2} seconds")
time.sleep(1)
print("The last one is coming up.")
time3 = get_reaction_time()
print(f"Your first time was {time3} seconds")
average = (time1 + time2 + time3) / 3
print(f"Your average time is {round_sig(average)} seconds")
This solution uses a Thread to start the timer, while the main thread waits for input all the time. That way, it is possible to catch early key presses:
from threading import Thread
import random
import time
def start():
global started
started = None
time.sleep(random.randint(2,5))
print("#### GO ####")
started = time.time()
t = Thread(target=start)
print("ready...")
# start the thread and directly wait for input:
t.start()
input()
end = time.time()
if not started:
print("Fail")
else:
print(end-started)
t.join()
I'am learning python by doing little projects on my own. I'am struggling to schedule scripts with random delay in a range.
In the code below, the delay is random but always the same ... I Really need help.
import schedule
import time
import random
import datetime
def job():
t = datetime.datetime.now().replace(microsecond=0)
print(str(t) + " hello")
i = 0
while i < 10:
delay = random.randrange(1, 5)
schedule.every(delay).seconds.do(job)
i += 1
while True:
schedule.run_pending()
time.sleep(1)
Think through your loops. Your first while loop creates a second infinite while loop. So you never continue to the function that would create a new delay.
import schedule
import time
import random
import datetime
def job():
t = datetime.datetime.now().replace(microsecond=0)
print(str(t) + " hello")
i = 0
for i in range(10):
delay = random.randrange(1, 5)
print(delay)
schedule.every(delay).seconds.do(job)
while True:
schedule.run_pending()
time.sleep(.01)
I started with a python program with curses, then I implemented threads, one which takes the input (here, the A and D buttons) and changes x accordingly. Then the main block continuously displays the value of x onto the screen. However, the values for x (a global, shared variable) are different. In particular, the value of x as measured by the main block always lags that of inputThread, but inputThread is perfectly responsive. What gives? How do I make the main block read the true value of x as measured by inputThread?
import time
import curses
import threading
from curses import wrapper
from time import sleep
def inputThread(stdscr):
global x
x = 0
while True:
c = stdscr.getch()
curses.flushinp()
if c == ord('a'):
x -= 1
elif c == ord('d'):
x += 1
stdscr.addstr("inputThread:" + str(x) + "\n" + "c:" + str(c))
def main(stdscr):
curses.initscr()
stdscr.clear()
t = threading.Thread(target=inputThread, args=(stdscr,))
t.setDaemon(True)
t.start()
while True:
stdscr.clear()
stdscr.addstr("\ndisplay window:" + str(x) + "\n")
time.sleep(0.05)
wrapper(main)
sample output; on next keypress, whether A or D, display window will report 9.
First of all, your global variable x should be declared outside all the functions but you have declared it inside the inputThread function. global x tells that instead of creating another variable within the function scope, it will use and alter the values of the global variable x. Hence delcare and initialize x with 0 outside the other functions.
Now comes your question. Suppose while the daemon and the main threads are running together, the daemon method just stuck at c = stdscr.getch() waiting for a key press while the while loop inside your main function in the main thread is doing nothing but only updating the sceen with the text display window: 0 which you can't see because the screen gets clear in 0.05s that the FPS is too fast to see the screen.
Now when you type either of those a or d keys, the daemon updates the value of the global variable x but before the main thread get that value, it is being printing on the virtual screen as InputThread:* and c:*** and the main thread prints only the previous value 0 in this case. So the workaround is to sleep the daemon thread for a while after updating x as in the meanwhile the loop inside the main thread will lead to display the newly updated value of x. This can be done in the following way:
import time
import curses
import threading
from curses import wrapper
from time import sleep
x = 0
def inputThread(stdscr):
global x
while True:
c = stdscr.getch()
curses.flushinp()
if c == ord('a'):
x -= 1
elif c == ord('d'):
x += 1
sleep(0.05)
stdscr.addstr("inputThread:" + str(x) + "\n" + "c:" + str(c))
def main(stdscr):
curses.initscr()
stdscr.clear()
t = threading.Thread(name ='daemon', target=inputThread, args=(stdscr,))
t.setDaemon(True)
t.start()
while True:
stdscr.clear()
stdscr.addstr("\ndisplay window:" + str(x) + "\n")
sleep(0.05)
wrapper(main)
Hope it helps.
I am trying to make a text based game in which the user is a pilot in space. I want to create a movement system but am unsure how to do it. I want the user to be able to put in the desired grid coordinates, and his vehicle will begin to change its grid coords to get closer and closer to the ones he inputted.
Now, to do this I will probably need multithreading and a time element. But I am unsure how I can use a time element. Any advice is greatly appreciate, i'm just trying to learn here. Thanks guys!
from Gundam2 import Mobilesuits
#Main Variable/Object declarations:
Leo1=Mobilesuits(100,100,"Leo","leo desc","dockpit desc",100,[100,100,100])
Leo2=Mobilesuits(100,100,"Leo","leo desc","dockpit desc",100,[300,100,100])
Leo3=Mobilesuits(100,100,"Leo","leo desc","dockpit desc",100,[100,150,100])
currentmobilesuit=Leo1
#Main Function declarations
def commands(user_input,currentmobilesuit):
if user_input == "radar":
currentmobilesuit.radar()
elif user_input == "commands":
print("Command list:\nradar")
else:
print("Invalid command\nType 'commands' for a list of valid commands")
#Main execution
while True:
commands(raw_input(),currentmobilesuit)
class Mobilesuits:
#class global variables/methods here
instances = [] #grid cords here
def __init__(self,armor,speed,name,description,cockpit_description,\
radar_range, coordinates):
Mobilesuits.instances.append(self)
self.armor=armor
self.speed=speed
self.name=name
self.description=description
self.cockpit_description=cockpit_description
self.radar_range=radar_range
self.coordinates=coordinates
def can_detect(self, other):
for own_coord, other_coord in zip(self.coordinates, other.coordinates):
if abs(own_coord - other_coord) > self.radar_range:
return False
return True
def radar(self):
for other in Mobilesuits.instances:
if other is not self and self.can_detect(other):
print "%s detected at %s" % (other.description, other.coordinates)
Games typically have a "master loop" of some kind; yours does here:
#Main execution
while True:
commands(raw_input(),currentmobilesuit)
The simplest thing to do is to count in the loop:
#Main execution
turn_count = 0
while True:
commands(raw_input(),currentmobilesuit)
turn_count += 1
If you wanted the real time taken to have some impact on the counter, or be the counter, you can get the current time from the time module calling time.time().
#Main execution
import time
time_start = time.time()
time_elapsed = 0
while True:
commands(raw_input(),currentmobilesuit)
time_elapsed = time.time() - time_start
A couple other thoughts:
Make a Game class, and put the turn counter and game loop in that.
Have the commands function return a number that is the number of time units that took place during the command; for example, entering an invalid command might take 0 turns, while repairing a robot might take 5.
#Main execution
turn_count = 0
while True:
turns_taken = commands(raw_input(),currentmobilesuit)
turn_count += turns_taken
You can use non-blocking I/O. This will help you avoid the complications of threading. Here's your sample code implemented with a non-blocking read of stdin:
#!/usr/bin/python
import sys
import select
call_count = 0
#Main Function declarations
def commands(user_input):
global call_count
if len(user_input) > 0:
print('call count: ' + str(call_count) + ' user entered: ' + user_input)
def raw_input_no_block():
global call_count
call_count = call_count + 1
input_avail = select.select([sys.stdin], [], [], 0.1)[0] #wait for 0.1 seconds
if input_avail:
return sys.stdin.readline()
else:
return ''
#Main execution
while True:
commands(raw_input_no_block())