How to add a pause in python without disrupting other code - python

I'm attempting to make a script that keeps the times of each boss in a game through text.
an example would be:
if line == 'boss1 down':
print('boss1 timer set for 10 seconds')
time.sleep(10)
print("boss1 due")
if line == 'boss2 down':
print('boss2 timer set for 15 seconds')
time.sleep(15)
print("boss2 due")
However, the clear issue is that only one boss can be timed at a time. Is there a function I can use that won't disrupt the code and allow me to time multiple at a given time?

You can use the Thread class from the built-in threading module:
from threading import Thread
import time
def timer(num, secs, line):
if line == f'boss{num} down':
print(f'boss{num} timer set for {secs} seconds ')
time.sleep(secs)
print(f"boss{num} due")
boss1 = Thread(target=timer, args=(1, 10, "boss1 down"))
boss2 = Thread(target=timer, args=(2, 15, "boss2 down"))
boss1.start()
boss2.start()
Output:
boss1 timer set for 10 seconds boss2 timer set for 15 seconds
boss1 due
boss2 due

You can use Asynchronous function :
import asyncio
async def boss1_down():
print('boss1 timer set for 10 seconds')
await asyncio.sleep(10)
print("boss1 due")
asyncio.run(boss1_down())
, add arguments to the function for timers and boss.
As #Mayank mentioned, you can also use threads, which are a bit more complex to settle but you can control them (you cannot stop or wait an async function).

From this answer
You can use threading to do asynchronous tasks.
from threading import Thread
from time import sleep
def threaded_function(line):
if line == 'boss1 down':
print('boss1 timer set for 10 seconds')
time.sleep(10)
print("boss1 due")
if line == 'boss2 down':
print('boss2 timer set for 15 seconds')
time.sleep(15)
print("boss2 due")
if __name__ == "__main__":
thread1 = Thread(target = threaded_function, args= 'boss1 down')
thread1.start()
thread1.join()
thread2 = Thread(target = threaded_function, args= 'boss2 down')
thread2.start()
thread2.join()
print("thread finished...exiting")

Related

How to measure time taken of multi-threads created in a loop?

I want to measure how much time it takes to finish running the code with multiple threads in python.
If I put join inside the loop, it will stop the loop (main thread) from keep creating new threads. It will run the sleep() one by one.
If I put join on the thread which I use to create thread_testing, the join won't work somehow. It prints out the time immediately.
def sleep(name):
print("{} going to sleep".format(name))
time.sleep(5)
print("{} wakes up after 5 seconds".format(name))
def thread_testing():
for i in range(3):
t = threading.Thread(target=sleep, name='thread' + str(i), args=(i,)
t.start()
# t.join() #1
if __name__ == '__main__':
start = time.time()
t = threading.Thread(target=thread_testing, name='threadx')
t.start()
t.join() #2
print(time.time() - start)
Desired output:
1 sleep
2 sleep
3 sleep
1 wake up after 5
2 wake up after 5
3 wake up after 5
5.xxx secs
Join will wait for your thread. That is why your threads were executed one by one.
What you have to do is:
Start all threads
Store them somewhere
Once everything is started wait for every thread to finish.
Assuming you don't need the first thread started in main:
import time
import threading
def sleep(name):
print("{} going to sleep".format(name))
time.sleep(5)
print("{} wakes up after 5 seconds".format(name))
def thread_testing():
threads = []
for i in range(3):
t = threading.Thread(target=sleep, name='thread' + str(i), args=(i,))
t.start()
threads.append(t)
for t in threads:
t.join()
if __name__ == '__main__':
start = time.time()
thread_testing()
print(time.time() - start)

How to interrupt input after 30 seconds and quit from program? - automatic logout - Python

I would like to make automatic logout after 30 seconds.
Program waits for user to input something and after 30 seconds I would like program to automatically shut down.
I have something like this:
import sys, time, os
def start_controller(user):
start = time.time()
PERIOD_OF_TIME = 30
os.system('clear')
print_menu() #printing menu
choice = get_choice() #get input from view model
while choice != "0":
os.system('clear')
if choice == "1":
start += PERIOD_OF_TIME
print_student_list(Student.student_list,AllAttendance.all_attendance_list)
if time.time() > start + PERIOD_OF_TIME:
os.system("clear")
print('logout')
Database.save_all_data_to_csv()
sys.exit()
Here's a simple example of using threads to get and process user input with a timeout.
We create a Timer thread to perform the timeout function, and wait for the user input in a daemon thread. If the user supplies an input string within the nominated delay period then the Timer is cancelled, otherwise the Timer will set the finished Event to break the while loop. If you need to do any final cleanup, you can do that after the while loop.
from threading import Thread, Timer, Event
def process_input(timer):
s = input('> ')
timer.cancel()
print(s.upper())
delay = 30
finished = Event()
while not finished.isSet():
timer = Timer(delay, finished.set)
worker = Thread(target=process_input, args=(timer,))
worker.setDaemon(True)
worker.start()
timer.start()
timer.join()

Daemon thread not exiting despite main program finishing

I've already referred to this thread, but it seems to be outdated
and there doesn't seem to be a clean explanation
Python daemon thread does not exit when parent thread exits
I'm running python 3.6 and trying to run the script from either IDLE or Spyder IDE.
Here is my code:
import threading
import time
total = 4
def creates_items():
global total
for i in range(10):
time.sleep(2)
print('added item')
total += 1
print('creation is done')
def creates_items_2():
global total
for i in range(7):
time.sleep(1)
print('added item')
total += 1
print('creation is done')
def limits_items():
#print('finished sleeping')
global total
while True:
if total > 5:
print ('overload')
total -= 3
print('subtracted 3')
else:
time.sleep(1)
print('waiting')
limitor = threading.Thread(target = limits_items, daemon = True)
creator1 = threading.Thread(target = creates_items)
creator2 = threading.Thread(target = creates_items_2)
print(limitor.isDaemon())
creator1.start()
creator2.start()
limitor.start()
creator1.join()
creator2.join()
print('our ending value of total is' , total)
limitor thread doesn't seem to be ending despite being a daemon thread.
Is this a way to get this working from IDLE or Spyder?
Thanks.
I had the same Problem and solved it by using multiprocessing instead of threading:
from multiprocessing import Process
import multiprocessing
from time import sleep
def daemon_thread():
for _ in range(10):
sleep(1)
print("Daemon")
if __name__ == '__main__':
multiprocessing.freeze_support()
sub_process = Process(target = daemon_thread, daemon = True)
sub_process.start()
print("Exiting Main")
I haven't yet really understood why I need the call to freeze_support() but it makes the code work.

sleep without interrupting program

I am creating a program that counts down after a time, and asks for input of seconds to add to the countdown. (Not really, just an example).
Kind of like this:
mytime = 10
while True:
print(time)
mytime -= 1
time.sleep(1)
mytime += int(input('add > '))
There is 2 problems.
I want the time to still tick down after a second, but don't want to have to wait the second before inputting. Similar to this. I think I need to use threading.
I don't want to wait for input either! I just want it to tick down without waiting for input, and when I want I can input things.
Thanks for your help.
There is an easier way than making your own thread from 0. Timer thread prepared for you:
import threading
timer = None
def wuf ():
global timer
print "Wuf-wuf!"
timer = threading.Timer(5, wuf)
timer.start()
timer = threading.Timer(5, wuf)
timer.start()
input() # Don't exit the program
This code will wait 5 seconds and then start printing "Wuf-wuf!" every 5 seconds.
If you want to stop it from main thread do:
timer.cancel()
But if you are writing a GUI application using event driven GUI system like wxPython or PyQT, then you should use theirs event managed timers. Especially if you are changing some GUI status from the timer callback.
Edit:
Oh, all right, here is your full answer:
import threading
seconds = 1 # Initial time must be the time+1 (now 0+1)
timer = None
def tick ():
global seconds, timer
seconds -= 1
if seconds==0:
print("%i seconds left" % seconds)
print("Timer expired!")
return
# printing here will mess up your stdout in conjunction with input()
print("%i second(s) left" % seconds)
timer = threading.Timer(1, tick)
timer.start()
seconds += int(input("Initial countdown interval: "))
tick()
while 1:
seconds += int(input("Add: "))
if not timer.is_alive():
print("Restarting the timer!")
seconds += 1
tick()
Or easy version with thread (but a little clumsyer then using threading.Thread):
from thread import start_new_thread as thread
from time import sleep
seconds = 1 # Initial time+1
alive = 0
def _tick ():
global seconds, alive
try:
alive = 1
while 1:
seconds -= 1
if seconds==0:
print("%i seconds left" % seconds)
print("Timer expired!")
alive = 0
return
# printing here will mess up your stdout in conjunction with input()
print("%i second(s) left" % seconds)
sleep(1)
except: alive = 0
def tick ():
thread(_tick,())
# Then same as above:
seconds += int(input("Initial countdown interval: "))
tick()
while 1:
seconds += int(input("Add: "))
if not alive:
print("Restarting the timer!")
seconds += 1
tick()
You must realize that using the stdout within a thread will insert the printed text after the prompt message outputed by input().
This will be confusing. If you want to avoid this then you will have to write another thread that will get messages from a queue and output them.
If a last message was prompt message, then you will have to remove it from screen, write the new message, then return the prompt message, and position the cursor accordingly.
You could do it by implementing the file-like interface within the subclass of threading.Thread, then substituting sys.stdout with it. Perhaps overriding input() as well to indicate when a prompt message is out and stdin being read.
You'll need to use threading to do so. All you have to do is create a subclass of threading.Thread override the run() method and add some external control methods over the thread.
Here is a simple example you can try and tweak according to your own taste.
import threading
import time
class SleepingThread(threading.Thread):
def __init__(self, sleep_for):
super(SleepingThread, self).__init__()
self.sleep_for = sleep_for
def run(self):
while self.sleep_for != 0:
time.sleep(1)
self.sleep_for -= 1
print("Done sleeping")
def add_seconds(self, seconds):
self.sleep_for += seconds
def get_sleep_for(self):
return self.sleep_for
sleeping_thread = SleepingThread(10)
sleeping_thread.start()
while True:
print(sleeping_thread.get_sleep_for())
sleeping_thread.add_seconds(int(input('add > ')))
Don't forget to join() if you want to go serious about it.

Small Example for pyserial using Threading

Can anyone please give me a small and simple example on how to use threading with pyserial communication.
I am googling for over three days and I am still illeterate and I dont even have a working piece of code which integrate both of them
Basically I am aiming to use threading in this scenario:
Have a serial communication continuously go on in the back ground to attain certain value (say A) from an MCU.
Stop attaining value A - then attain value B...and start continuously attaining value A again.
You can find some basic code here.
import threading
import time
import sys
import serial
import os
import time
def Task1(ser):
while 1:
print "Inside Thread 1"
ser.write('\x5A\x03\x02\x02\x02\x09') # Byte ArrayTo Control a MicroProcessing Unit
b = ser.read(7)
print b.encode('hex')
print "Thread 1 still going on"
time.sleep(1)
def Task2(ser):
print "Inside Thread 2"
print "I stopped Task 1 to start and execute Thread 2"
ser.write('x5A\x03\x02\x08\x02\x0F')
c = ser.read(7)
print c.encode('hex')
print "Thread 2 complete"
def Main():
ser = serial.Serial(3, 11520)
t1 = threading.Thread(target = Task1, args=[ser])
t2 = threading.Thread(target = Task2, args=[ser])
print "Starting Thread 1"
t1.start()
print "Starting Thread 2"
t2.start()
print "=== exiting ==="
ser.close()
if __name__ == '__main__':
Main()
There's no factual basis for the claim by Task2:
print "I stopped Task 1 to start and execute Thread 2"
Your implementation starts one thread then immediately starts the other without stopping the first. This means that the ser.read and ser.write commands could interfere with each other.
The simplest thing you could do to address this is to introduce variables that allow communication:
import sys
import os
import time
import threading
thread_flag = None
def Report(s):
print s
sys.stdout.flush() # helps to ensure messages from different threads appear in the right order
def Stop():
global thread_flag
thread_flag = 'stop'
def Task1(ser):
Report("Inside Thread 1")
global thread_flag
thread_flag = 'go'
while True:
Report("Thread 1 waiting for permission to read")
while thread_flag != 'go': time.sleep( 0.001 )
while thread_flag == 'go':
Report("Thread 1 is reading")
#ser.write('\x5A\x03\x02\x02\x02\x09') # Byte ArrayTo Control a MicroProcessing Unit
#b = ser.read(7)
#Report(b.encode('hex'))
time.sleep(1)
if thread_flag == 'stop': break
else: thread_flag = 'paused' # signals that the inner loop is done
Report("Thread 1 complete")
def Task2(ser):
Report("Inside Thread 2")
global thread_flag
thread_flag = 'pause' # signals Task1 to pause
while thread_flag != 'paused': time.sleep(0.001) # waits for Task1 inner loop to exit
Report("I stopped Task 1 to start and execute Thread 2")
#ser.write('x5A\x03\x02\x08\x02\x0F')
#c = ser.read(7)
#Report(c.encode('hex'))
thread_flag = 'go' # signals Thread 1 to resume
Report("Thread 2 complete")
def Main():
ser = None # serial.Serial(3, 11520)
t1 = threading.Thread(target = Task1, args=[ser])
t2 = threading.Thread(target = Task2, args=[ser])
Report("Starting Thread 1")
t1.start()
time.sleep(3)
Report("Starting Thread 2")
t2.start()
if __name__ == '__main__':
Main()
That approach uses a global variable, which is often frowned upon. You could instead make Task1 and Task2 methods of an object self that carries both self.ser and self.thread_flag as attributes.
For any inter-thread communication more complex than this, you need to investigate locks, mutexes and semaphores (e.g. threading.Lock)

Categories

Resources