In my case, I want to hook the keyboard keys that is pressed.
And when I press "0", I want to kill the terminal.
Both functions should work at the same time.
But my code doesn't work. What is wrong with this code?
import keyboard
import asyncio
def sleep(a):
rand1 = random.uniform(0, 0.009)
rand2 = random.uniform(0.01, 0.02)
result = random.uniform(rand1, rand2)
asyncio.sleep(a + result)
async def record_start():
while True:
k = keyboard.read_key()
k = keyboard.read_key()
print(k)
async def record_stop():
while True:
if keyboard.is_pressed('0'):
print('stop')
sleep(1)
exit()
async def main():
await asyncio.gather(
record_stop(),
record_start(),
)
asyncio.run(main())
I tried out using another modules.
And I assume that problem is modules or way to use "while"
your record_start function never gives a chance to any other async code to run.
Introduce an awaiting call in it, like await asyncio.sleep(.01) in it (it may be sleep(0) but I'd advise a larger interval), and things should work.
I just solved this issue.
It doesn't need to use 'asyncio' module.
instead, I run this code with 'threading' module.
from threading import Thread
import os
def thread_1():
while True:
start_time = time.time()
k = keyboard.read_key()
k = keyboard.read_key()
print("sleep(%s)" % round(time.time() - start_time, 3))
print("press('%s')" % k)
def thread_2():
while True:
if keyboard.is_pressed('0'):
print('stop')
pid = os.getpid()
os.kill(pid, 2)
if __name__ == "__main__":
t1 = Thread(target=thread_1)
t2 = Thread(target=thread_2)
print('start')
t1.start()
t2.start()
Related
I have a queue variable and an input order. In case the queue has something, I have to force the input order to stop. I have had to use asyncio module to do that. As a example, let's see the following code:
import asyncio
import multiprocessing
import time
from aioconsole import ainput
def my_function(queue):
time.sleep(3)
queue.put(5)
async def my_loop(queue):
while True:
await asyncio.sleep(0.1)
if not queue.empty():
break
async def main():
queue = multiprocessing.Queue()
p = multiprocessing.Process(target=my_function, args=(queue,))
p.start()
task1 = asyncio.create_task(ainput("Enter text:"))
task2 = asyncio.create_task(my_loop(queue))
await asyncio.wait([task1, task2], return_when='FIRST_COMPLETED')
try:
text = task1.result()
q = ""
except asyncio.exceptions.InvalidStateError:
text = ""
q = queue.get()
print('Doing stuff with input %s/%s...' % (text, q))
This works perfectly and the program ends whenever the queue has something on it or the user inputs some text. My real program has several input orders like this in a row, something like this:
import asyncio
import multiprocessing
import time
from aioconsole import ainput
def my_function(queue):
time.sleep(3)
queue.put(5)
async def my_loop(queue):
while True:
await asyncio.sleep(0.1)
if not queue.empty():
break
async def main():
queue = multiprocessing.Queue()
p = multiprocessing.Process(target=my_function, args=(queue,))
p.start()
task1 = asyncio.create_task(ainput("Enter text:"))
task2 = asyncio.create_task(my_loop(queue))
await asyncio.wait([task1, task2], return_when='FIRST_COMPLETED')
try:
text = task1.result()
q = ""
except asyncio.exceptions.InvalidStateError:
text = ""
q = queue.get()
print('Doing stuff with input %s/%s...' % (text, q))
task1 = asyncio.create_task(ainput("Next: "))
task2 = asyncio.create_task(my_loop(queue))
await asyncio.wait([task1, task2], return_when='FIRST_COMPLETED')
try:
text = task1.result()
q = ""
except asyncio.exceptions.InvalidStateError:
text = ""
q = queue.get()
print('Doing stuff with input %s/%s...' % (text, q))
if __name__ == '__main__':
asyncio.run(main())
The problem is that, if I wait for the queue the first time, the second time, I have to enter the input twice, like if the first input was still waiting or something. Do you know how can I definitely "break" the first input if the user doesn't write anything? Thanks in advance
If I understand you correctly, you can use use task.cancel() between the steps cancel all pending tasks:
import asyncio
import multiprocessing
import time
from aioconsole import ainput
def my_function(queue):
time.sleep(3)
queue.put(5)
async def my_loop(queue):
while True:
await asyncio.sleep(0.1)
if not queue.empty():
break
async def main():
queue = multiprocessing.Queue()
p = multiprocessing.Process(target=my_function, args=(queue,))
p.start()
task1 = asyncio.create_task(ainput("Enter text:"))
task2 = asyncio.create_task(my_loop(queue))
tasks = [task1, task2]
await asyncio.wait(tasks, return_when="FIRST_COMPLETED")
try:
text = task1.result()
q = ""
except asyncio.exceptions.InvalidStateError:
text = ""
q = queue.get()
print()
print("1. Doing stuff with input %s/%s..." % (text, q))
# cancel all tasks:
for t in [task1, task2]:
t.cancel()
# Wait until all worker tasks are cancelled:
await asyncio.gather(*tasks, return_exceptions=True)
task1 = asyncio.create_task(ainput("Next: "))
task2 = asyncio.create_task(my_loop(queue))
tasks = [task1, task2]
await asyncio.wait(tasks, return_when="FIRST_COMPLETED")
try:
text = task1.result()
q = ""
except asyncio.exceptions.InvalidStateError:
text = ""
q = queue.get()
print()
print("2. Doing stuff with input %s/%s..." % (text, q))
if __name__ == "__main__":
asyncio.run(main())
Prints (for example):
Enter text:
1. Doing stuff with input /5...
Next: Hello World
2. Doing stuff with input Hello World/...
I am trying to run two functions in parallel:
Timer
Input field
Program should terminate either when Timer ends or when user provides an answer.
Everything is working fine, but when the time is up I still can input an answer, and I want process to terminate.
Can somebody help me with that issue ?
Thanks !
Here is my code:
import sys
import time
import threading
def countdown2(seconds):
global stop_timer
stop_timer = False
start = time.time()
while not stop_timer:
if time.time() - start >= seconds:
stop_timer = True
print(f'End of time {time.time() - start}')
print(f'End of time in {time.time() - start}')
countdown_thread = threading.Thread(target=countdown2, args=(5,))
countdown_thread.start()
while not stop_timer:
answer = input('Provide answer: ')
if answer:
stop_timer = True
break
print('End')
Here's an example of how you could do this:
from threading import Thread
import time
import signal
import os
got_input = False
def countdown(duration):
global got_input
for _ in range(duration):
time.sleep(1)
if got_input:
return
if not got_input:
os.kill(os.getpid(), signal.SIGINT)
def main():
global got_input
(t := Thread(target=countdown, args=[5])).start()
try:
answer = input('Please enter a value: ')
got_input = True
print(f'You entered: {answer}')
except KeyboardInterrupt:
print('\nToo slow')
finally:
t.join()
if __name__ == '__main__':
main()
I am coding a discord bot with python, I am running into difficulties with the next feature. When the message: ('user' joined) is read the bot should start looping the function every x seconds until the message: ('user' left) is read.
I have been testing different code in scratch files. It succesfully starts looping at 'user' joined. But when the ('user' left) message should come through it won't take the new argument and continues the loop forever.
These two versions look most promising:
import re
import time
def message(servermessage):
a = re.sub("[^\S]", " ", servermessage).split()
if a[1] == 'joined':
online = False
elif a[1] == 'left':
online = True
while True:
mcusername = a[0]
print(mcusername, 0)
if online:
break
time.sleep(2)
message('user joined')
time.sleep(10)
message('user left')
and
import re
import sched, time
s = sched.scheduler(time.time, time.sleep)
def message(servermessage):
a = re.sub("[^\S]", " ", servermessage).split()
def rewardplayer():
s.enter(1, 1, rewardplayer)
mcusername = a[0]
print(mcusername, 0)
if a[1] == 'joined':
s.enter(1, 1, rewardplayer)
s.run()
elif a[1] == 'left':
s.cancel()
message('user joined')
time.sleep(10)
print('done')
message('user left')
Another requirement that I have is that it should be able to run the same loop for a different user when a ('newuser' joined) message is given before the ('previoususer' left) message from a previous user.
I apologise for the vague explanation. But I hope you can help. Thanks in advance!
About your first code:
there you have while which should be broken when online is True. But its never changing inside that loop. So its similar to deadlock.
About your second code:
there you are using "scheduler". Usually it means you want to run some events periodically. But your aim is to react when event was happened. In any time. Not schedulled.
So here I can recommend you to use async python way.
(please, read about asyncio)
import re
import asyncio
async def process_msgs(queue):
while True:
msg = await queue.get()
online, usr_name = parse_msg(msg)
print(usr_name, 0)
queue.task_done()
def parse_msg(msg):
result = re.sub("[^\S]", " ", msg).split()
action = result[1]
usr_name = result[0]
if action == 'joined':
online = False
elif action == 'left':
online = True
return online, usr_name
async def main():
queue = asyncio.Queue()
queue.put_nowait('usr joined')
task = asyncio.create_task(process_msgs(queue))
queue.put_nowait('usr left')
await queue.join()
task.cancel()
asyncio.run(main())
You can use it like that.
There we have a queue, where we put our events. You can do that through infinite way too (listen socket or smthg - here you will get msg about different users).
And we have task (worker), which work while our "main" function is alive.
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.
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)