I checked threads and solutions about multiprocessing on pyhton 3, but could not adapt it to my case because its containing a loop:
import time
anotherFunctionRunning = False
def anotherFunction():
global anotherFunctionRunning
anotherFunctionRunning = True
print("Another function started")
time.sleep(5)
print("Another function stopped running")
anotherFunctionRunning = False
def mainLoop():
global anotherFunctionRunning
while True:
print("running")
time.sleep(1)
if (anotherFunctionRunning == False):
anotherFunction()
else:
print("loop running, another function running")
print("loop ended")
mainLoop()
My problem here is when anotherFunction starts running, script waits it to be over (in the example 5 seconds) and continues the loop.
I want it to continue the loop while anotherFunction running.
I saw this common solution but could not adapt it to my case and dont know how to do because its becoming too complex:
from multiprocessing import Process
def func1:
#does something
def func2:
#does something
if __name__=='__main__':
p1 = Process(target = func1)
p1.start()
p2 = Process(target = func2)
p2.start()
Any ideas ?
Thanks for support
I'm not sure I understand what you want, but I think this should do the job
import time
from threading import Thread
anotherFunctionRunning = False
def anotherFunction():
global anotherFunctionRunning
anotherFunctionRunning = True
print("Another function started")
time.sleep(5)
print("Another function stopped running")
anotherFunctionRunning = False
def mainLoop():
global anotherFunctionRunning
thread = None
counter = 0
while counter < 5:
counter += 1
print("running")
time.sleep(1)
if anotherFunctionRunning == False:
thread = Thread(target= anotherFunction, name="AnotherThread")
thread.start()
else:
print("loop running, another function running")
print("loop ended")
thread.join()
mainLoop()
Beware however I have royally ignored the dangers of competitive access
Related
i have a thread running on the background checking every 5 sec and print a msg after 5 secs passes.
in loop1 the msg should appear at specific point. (in this case, its above print('test')).
the thread can wait longer than 5 secs when loop1 is running (like a few sec delay is fine) but it have not to appear at the same time as loop1 is running so i put queue to for blocking.
when loop2 is running, the messsage in the multithread should appear while loop2 is running at the same time unlike loop no1.
so i didnt put queue.get in loop2 since theres no need for blocking but the problem is when going into loop3. if we go into loop3 while we are on time.sleep(5) in multithread, thats fine but if we are on print ("thread working2") in multithread, i want to make sure it waits until it does all the work in print ("thread working2") part. there are more codes there but i just put a simple print for better readability. before going into loop3. is there any way i can accomplish this? and is the method im using right now is suitable for my intention?
sorry for my bad english!
import threading
import time
from queue import Queue
queue = Queue()
queue2 = Queue()
switch = False
def func0():
while True:
global switch
global queue
global queue2
time.sleep(5)
switch = True
print ("switch on")
a = queue.get()
if a == 1:
print("thread working")
time.sleep(0.5)
print("thread working")
time.sleep(0.5)
switch = False
queue2.put(True)
if a == 2:
print("thread working2")
time.sleep(0.5)
print("thread working2")
time.sleep(0.5)
switch = False
if __name__ == "__main__":
t1 = threading.Thread(target=func0)
t1.start()
testnumber = 0
testnumber2 = 0
testnumber3 = 0
while True: #loop no.1
if switch:
queue.put(1)
queue2.get()
print ("loop1")
time.sleep(0.5)
testnumber = testnumber +1
if testnumber == 200:
break
while True: #loop no.2
if switch:
queue.put(2)
print ("loop2")
time.sleep(0.5)
testnumber2 = testnumber2 + 1
if testnumber2 == 200:
break
while True: #loop no.3
print ("loop3")
time.sleep(0.5)
testnumber3 = testnumber3 + 1
if testnumber3 == 200:
break
t1.join()
As a new programmer, I'm trying to create a Python3 script that creates a Countdown timer based on the KeyCombination used which is then written to a text file used by StreamlabsOBS. The idea is that when a KeyCombo is pressed (e.g ctrl+alt+z) a function starts a timer, and at the same time, another function writes the current time in the countdown to a txt file. This script would ideally be running during the entire stream.
So far, I can get the countdown working and writing to the file exactly how I want it to. But it seems the Thread is still alive after finishing the countdown. I'm not sure if this is a problem or not. Another thing is that I want to implement some kind of pause feature, that would pause the timer function. I'm not sure how to even start on that part.
The print statements are for me to know what part of the function I am at.
from pynput import keyboard
from pathlib import Path
from threading import Thread
import queue
from time import sleep
script_location = Path(__file__).absolute().parent
timer_queue = queue.Queue()
def storeInQueue(function):
print("Sent Start Thread msg")
def storer(*args):
for time in function(*args):
timer_queue.put(time)
print(f"stored {time}")
return storer
#storeInQueue
def timer(t):
print("Iterating Timer Loop")
while t > -1:
yield t
sleep(1)
t -= 1
def speakKorean():
print("starting Thread")
timer_thread = Thread(target=timer, args=(5,))
timer_thread.start()
ctime = timer_queue.get()
while ctime >-1:
with open(script_location / 'ChronoDown.txt', "w") as timer_file:
timer_file.write(f"Speak Korean for {ctime}s")
timer_file.flush()
sleep(1)
ctime = timer_queue.get()
if ctime == 0: break
print('Speak Korean done!')
with open(script_location / 'ChronoDown.txt', "w") as timer_file:
timer_file.write(f"Done!")
timer_file.flush()
while timer_thread.is_alive:
print("timer thread still running?")
timer_thread.join()
break
if timer_thread.is_alive:
print("didn't work")
def on_activate_z():
timer_file = open(script_location / 'ChronoDown.txt', "w")
timer_file.write("other keywords")
timer_file.close()
def on_activate_c():
korean_thread = Thread(target=speakKorean,)
korean_thread.start()
print("Working")
def on_activate_x():
timer_file = open(script_location / 'ChronoDown.txt', "w")
timer_file.write("No cursing for time")
timer_file.close()
with keyboard.GlobalHotKeys({
'<ctrl>+<alt>+z': on_activate_z,'<ctrl>+<alt>+c': on_activate_c,
'<ctrl>+<alt>+x': on_activate_x}) as h:
h.join()
My console output looks like this after I run it. I'm not sure why "Sent Start Thread msg" sends before I start thread too.
Sent Start Thread msg
starting Thread
Working
Iterating Timer Loop
stored 5
stored 4
stored 3
stored 2
stored 1
stored 0
Speak Korean done!
timer thread still running?
didn't work
Also if you have any optimization tips that would be appreciated. Thank you in advance for any help.
Thanks to #furas , I've now implemented a pause function that properly resumes as well. This is my updated code :
from pynput import keyboard
from pathlib import Path
from threading import Thread
import queue
from time import sleep
script_location = Path(__file__).absolute().parent
timer_queue = queue.Queue()
paused = False
while paused == False:
def storeInQueue(function):
print("Sent Start Thread msg")
def storer(*args):
for time in function(*args):
timer_queue.put(time)
print(f"stored {time}")
return storer
#storeInQueue
def timer(t):
print("Iterating Timer Loop")
while t > -1:
if paused == False:
yield t
sleep(1)
t -= 1
else: continue
def speakKorean():
print("starting Thread")
timer_thread = Thread(target=timer, args=(5,))
timer_thread.start()
ctime = timer_queue.get()
while ctime >-1:
with open(script_location / 'ChronoDown.txt', "w") as timer_file:
timer_file.write(f"Speak Korean for {ctime}s")
timer_file.flush()
sleep(1)
ctime = timer_queue.get()
if ctime == 0: break
print('Speak Korean done!')
with open(script_location / 'ChronoDown.txt', "w") as timer_file:
timer_file.write(f"Done!")
timer_file.flush()
timer_thread.join()
if timer_thread.is_alive():
print("didn't work")
else: print("its dead")
def on_activate_z():
global paused
timer_file = open(script_location / 'ChronoDown.txt', "w")
timer_file.write("Paused")
timer_file.close()
if paused == True:
paused = False
print(f'Paused = {paused}')
else:
paused =True
print(f'Paused = {paused}')
def on_activate_c():
korean_thread = Thread(target=speakKorean,)
korean_thread.start()
print("Working")
def on_activate_x():
timer_file = open(script_location / 'ChronoDown.txt', "w")
timer_file.write("No cursing for time")
timer_file.close()
with keyboard.GlobalHotKeys({
'<ctrl>+<alt>+z': on_activate_z,'<ctrl>+<alt>+c': on_activate_c,
'<ctrl>+<alt>+x': on_activate_x}) as h:
h.join()
The main differences:
My entire code is now encapsulated in a While paused == False loop, which allows me to pause my timer function based on the state of paused using an if statement
I've added the missing ( ) to timer_thread.is_alive() which allowed me to properly end the timer Thread
Hey I am trying to have a loop be pausable from user input like having a input box in the terminal that if you type pause it will pause the loop and then if you type start it will start again.
while True:
#Do something
pause = input('Pause or play:')
if pause == 'Pause':
#Paused
Something like this but having the #Do something continually happening without waiting for the input to be sent.
Ok I get it now, here is a solution with Threads:
from threading import Thread
import time
paused = "play"
def loop():
global paused
while not (paused == "pause"):
print("do some")
time.sleep(3)
def interrupt():
global paused
paused = input('pause or play:')
if __name__ == "__main__":
thread2 = Thread(target = interrupt, args = [])
thread = Thread(target = loop, args = [])
thread.start()
thread2.start()
You can't directly, as input blocks everything until it returns.
The _thread module, though, can help you with that:
import _thread
def input_thread(checker):
while True:
text = input()
if text == 'Pause':
checker.append(True)
break
else:
print('Unknown input: "{}"'.format(text))
def do_stuff():
checker = []
_thread.start_new_thread(input_thread, (checker,))
counter = 0
while not checker:
counter += 1
return counter
print(do_stuff())
I have some background task that i want to start an be able to safely quit by user input.
To do that i have a thread in which a process pool with a continous task is started. There is a input lock to stop printing and to wait for user input and a event to stop the whole process.
What surprises me is that the processes seem to start and do their work if there is a time.sleep after the start of the thread with processpool (6th line in main).
import multiprocessing as mp
import time
import threading as tr
def init(e, l):
global stop_event
global input_lock
stop_event = e
input_lock = l
def stupid_task(n):
while not stop_event.is_set():
with input_lock:
print(n)
time.sleep(2)
def test_mng(n, event, lock):
with mp.Pool(n, initializer=init, initargs=(event, lock,)) as p:
print("before")
p.map(stupid_task, range(1, n + 1))
print("after")
p.close()
p.join()
def main():
i_lock = mp.Lock()
s_event = mp.Event()
thread = tr.Thread(target=test_mng, args=(3, s_event, i_lock))
init(s_event,i_lock)
thread.start()
time.sleep(1) # if this line is commented out only "before" is printed
while not stop_event.is_set():
input("")
with input_lock:
print("stopped")
eingabe = input("type q to quit")
if eingabe == "q":
stop_event.set()
if __name__ == "__main__":
main()
I ask myself what is stopping the process pool from doing it's work. Do i do something fundamentally wrong? The time.sleep seems a little bit hacky.
I my opinion, you are running your script from an IDE (like PyCharm), but not from the Console. Your IDE is catching the keyboard events.
You can simplify the processing:
The main process can wait for the user input,
The thread can do the "stupid task".
Here is a possible solution:
# coding: utf-8
import multiprocessing as mp
import threading as tr
import time
stop_event = None
def init(event):
global stop_event
stop_event = event
def stupid_task(n):
while not stop_event.is_set():
print(n)
time.sleep(2)
def test_mng(n, event):
with mp.Pool(n, initializer=init, initargs=(event,)) as p:
print("before")
p.map(stupid_task, range(1, n + 1))
print("after")
p.close()
p.join()
def main():
print("type 'q' <ENTER> to quit")
s_event = mp.Event()
init(s_event)
thread = tr.Thread(target=test_mng, args=(3, s_event,))
thread.start()
while not stop_event.is_set():
c = input("")
if c in "qQ":
stop_event.set()
if __name__ == "__main__":
main()
This question already has answers here:
Is there any way to kill a Thread?
(31 answers)
Closed 6 years ago.
i've got this code, how can I stop func2 from func1? something like Thread(target = func1).stop() doesn't work
import threading
from threading import Thread
def func1():
while True:
print 'working 1'
def func2():
while True:
print 'Working2'
if __name__ == '__main__':
Thread(target = func1).start()
Thread(target = func2).start()
It's better to ask your other thread to stop, using a message queue for instance.
import time
import threading
from threading import Thread
import Queue
q = Queue.Queue()
def func1():
while True:
try:
item = q.get(True, 1)
if item == 'quit':
print 'quitting'
break
except:
pass
print 'working 1'
def func2():
time.sleep(10)
q.put("quit")
while True:
time.sleep(1)
print 'Working2'
if __name__ == '__main__':
Thread(target = func1).start()
Thread(target = func2).start()
You cannot tell a thread to stop, you have to make it return in its target function
from threading import Thread
import Queue
q = Queue.Queue()
def thread_func():
while True:
# checking if done
try:
item = q.get(False)
if item == 'stop':
break # or return
except Queue.Empty:
pass
print 'working 1'
def stop():
q.put('stop')
if __name__ == '__main__':
Thread(target=thread_func).start()
# so some stuff
...
stop() # here you tell your thread to stop
# it will stop the next time it passes at (checking if done)