I created threads, added delay in the function, but all threads are executing at the same time. Instead i want threads to start one by one. Is that possible ?
Below is my code
from _thread import start_new_thread
import time
def mul(n):
time.sleep(1)
res = n * n
return res
while 1:
m = input("Enter number ")
t = input("Enter the number of times the function should be executed:")
max_threads = int(t)
for n in range(0, max_threads):
start_new_thread(mul, (m,))
except:
pass
print("Please type only digits (0-9)")
continue
print(f"Started {max_threads} threads.")
First of all, you added the delay inside the thread, causing it to pause after it started. Thus, you are starting all the threads one by one without delay and when each thread starts it waits 1 second before continuing.
So if you want a specific delay - add after you start each thread, in the main thread.
If you want each thread to start after the previous thread finished, you can do the following:
import threading
.
.
.
for n in range(0, max_threads):
t = threading.Thread(target = mul, args=(m,))
t.start()
t.join() # Waits until it is finished
Related
I want my code to take some integers for some time (e.g. 10 seconds) and to count and print time every second. So it prints time permanently and i enter some numbers whenever i want. Maybe i should use async functions?
def accepting_bets():
global list_of_bets
list_of_bets = []
list_of_bets.append(int(input()))
def main():
i = 10
while True:
print(f"{i} seconds remaining...")
time.sleep(1)
i -= 1
accepting_bets()
if i == 0:
break
print(list_of_bets)
You can move the timing code to a different thread.
I would recommend researching about multi-threading in Python if you aren't aware about it.
import threading
import time
def countTime():
i = 10
while True:
print(f"{i} seconds remaining...")
time.sleep(1)
i -= 1
if i == 0:
break
print(list_of_bets)
thread1 = threading.Thread(target=countTime)
thread1.start()
# while you want to get the input
global list_of_bets
list_of_bets = []
list_of_bets.append(int(input()))
The countTime function will keep on running on another thread, and will not be paused by the input statement
Description: now, I have done input and countdown, both of which are carried out at the same time, but I want to achieve like this:
When I don't input anything during the countdown, it will execute another function after the countdown
When I input something before the end of the countdown, the countdown will pause, and then another function will be executed
My code is as follows:
import time
from threading import Thread
def waitinput():
wait_input_str = input("Please enter your account:\n")
print(wait_input_str)
thd = Thread(target=waitinput)
thd.daemon = True
thd.start()
for i in reversed(range(1, 11)):
print("\rcountdown:{}second".format(i), end="")
time.sleep(1)
# ###########################################
You can use isAlive() method to check if your thread has terminated.
In your case:
import time
from threading import Thread
def waitinput():
wait_input_str = input("Please enter your account:\n")
print(wait_input_str)
thd = Thread(target=waitinput)
thd.daemon = True
thd.start()
for i in reversed(range(1, 11)):
if not thd.isAlive():
# Execute 2
print("\nCountdown has stopped")
break
print("\rcountdown:{}second".format(i), end="")
time.sleep(1)
if thd.isAlive():
# Execute 1
print("\nCountdown has ended")
I am trying to figure out how in python one would declare a specific variable to be locked so that only one thread may access it at a time to avoid race conditions. If I have two threads constantly updating a variable via queues, but I am also updating the variable manually in main, what would be the right way to declare that variable a shared resource by all threads so that only one may access it at a time between the threads being run and main?
I wrote a little example code to show what I mean.
import time
from random import randint
from threading import Thread
from queue import Queue
# Add the amount by random number from 1 - 3 every second
def producer(queue, amount):
while True:
time.sleep(1)
amount[0] += randint(1, 3)
queue.put(amount)
# Subtract the amount by random number from 1 - 3 every second
def consumer(queue, amount):
while True:
item = queue.get()
amount[0] -= randint(1, 3)
queue.task_done()
amount = [10]
queue = Queue()
t1 = Thread(target=producer, args=(queue, amount,))
t2 = Thread(target=consumer, args=(queue, amount,))
t1.start()
t2.start()
while True:
n = input("Type a number or q: ")
if n == 'q':
break
else:
# Here is where I am confused about how to declare the amount a
# shared resource and lock it in a way that the queues would also
# adhere to
amount[0] += int(n)
print("amount is now: {}".format(amount[0]))
t1.join()
t2.join()
It is important to lock the variable when you are updating the value of it. so in your case indeed you require locking mechanism.
How to lock:
create a threading.Lock object which will help you lock and release the block of code.
acquire : to lock the code block. only one thread can enter in this block. other thread will wait until it is released.
release : to release the acquired lock.
In your case:
import time
from random import randint
from threading import Thread,Lock
from queue import Queue
# Add the amount by random number from 1 - 3 every second
def producer(queue, amount,lock):
while True:
time.sleep(1)
lock.acquire()
amount[0] += randint(1, 3)
queue.put(amount)
lock.release()
# Subtract the amount by random number from 1 - 3 every second
def consumer(queue, amount,lock):
while True:
lock.acquire()
item = queue.get()
amount[0] -= randint(1, 3)
queue.task_done()
lock.release()
amount = [10]
lock = Lock()
queue = Queue()
t1 = Thread(target=producer, args=(queue, amount,lock))
t2 = Thread(target=consumer, args=(queue, amount,lock))
t1.start()
t2.start()
...
I have a raspberry PI 2. With a relay board, what i use to for a switch sequence (like a traffic light).
I use a tool, called "webiopi" what create buttons on a website. When the button is clicked the function of the python script below is started.
What i want is to break out of the loop (or pause it) when another button is clicked. However, as long this loop is running, the tool don't look at the webpage
A kind of similar question is asked here Exiting a continuous loop in python via webiopi but this is for a single event and the solution doesn't work in my case.
Question is. How can I make this script look at a button what is clicked (can be a gpio switch as well) while the loop is running
GPIO_nek=11
GPIO_schouder=12
GPIO_rug1=8
GPIO_ONOFF=18
interval1 = 2
interval2 = 4
for x in range(0, 20):
GPIO.digitalWrite(GPIO_nek, GPIO.LOW)
time.sleep(interval1)
GPIO.digitalWrite(GPIO_schouder, GPIO.LOW)
time.sleep(interval1)
GPIO.digitalWrite(GPIO_nek, GPIO.HIGH)
time.sleep(interval1)
GPIO.digitalWrite(GPIO_rug1, GPIO.LOW)
time.sleep(interval2)
GPIO.digitalWrite(GPIO_schouder, GPIO.HIGH)
if (GPIO.digitalRead(GPIO_ONOFF) == GPIO.LOW):
GPIO.digitalWrite(GPIO_ONOFF, GPIO.HIGH)
break
When monitoring a real time event such as sensors or your button your best solution will be setting up a separate thread or process that contains nothing but an infinite loop that watches the resource and sets a flag when something interesting happens.
The example below sets up a process that automatically takes a picture on the RPI aprox. every minute.
#!/usr/bin/python
#Threading Prototype - Running a background thread that will take
# pictures at the appropriate time
#------------------------------------------------------------------
from multiprocessing import Queue
from multiprocessing import Process
from time import sleep
from datetime import datetime
from datetime import timedelta
from subprocess import call
#Doing the work ---------------------------------------------------
#Global Variables ---
messages = Queue()
start_time = datetime.now()
#Returns number of Milliseconds since start of program
def milliSinceStart():
global start_time
dt = datetime.now() - start_time
ms = (dt.days * 24 * 60 * 60 + dt.seconds) * 1000 + dt.microseconds / 1000.0
return ms
#Process Methods --------------------------------------------------
def processMessages():
print "Message Processor Launched"
while True:
print messages.get() #should halt until message in queue
sleep(0.1) #sleep for a tick just to avoid a run away process
def processPicutres():
print "Picture Taker Launched"
pictureCycleStart = milliSinceStart()
index = 0
while True:
if milliSinceStart() - pictureCycleStart > 10000: #once a minute
a = "blip" + str(index) + ".jpg"
b = "raspistill -n -t 100 -o " + a
messages.put("Click")
call ([b], shell=True)
messages.put("picture taken - " + b)
index = index + 1
pictureCycleStart = milliSinceStart()
sleep(0.1) #wait a tick -- don't hog processor time
def main():
print "MultiProcessing Prototype"
print "Launching message process"
Process(target=processMessages).start()
print "Back from launch"
print "Launching picture taking process"
Process(target=processPicutres).start()
print "Back from launch"
cycleStart = milliSinceStart()
index = 0
while True:
if milliSinceStart() - cycleStart > 1000:
messages.put("Tick " + str(index))
cycleStart = milliSinceStart()
index = index + 1
if __name__ == "__main__":
main()
The main method launches the Messaging and Picture processes and then sets up its own little infinite loop that does nothing more that display the message "Tick" every second. The picture process sets up a separate infinite loop, watching the clock and taking a picture periodically. The Message process monitors the picture process (again, an infinite loop) and when it detects that a picture has been taken, it outputs the fact to the screen.
The important part of this for your purpose is the message queue. The process queue is what is allowing the Picture and Message processes to communicate.
And because the task take place in different processes, it matters not if one process pauses as the others are always active. If you set up a button monitor process you can be checking message queue for this fact and halting your main program when the button is pressed. This pause in the main program would not effect the button process which could then pick up on the fact that the button is pressed again.
If the button is the GPIO switch as you mentioned at the end of the question, instead of the webpage button, then you can make use of an inbuilt GPIO interrupt function that saves your computer the resouces of constant polling:
import RPi.GPIO as GPIO
from threading import Event # We'll use it like time.sleep, but we can interrupt it.
GPIO_nek=11
GPIO_schouder=12
GPIO_rug1=8
GPIO_ONOFF=18
interval1 = 2
interval2 = 4
GPIO.setup(GPIO_ONOFF, GPIO.IN, pull_up_down=GPIO.PUD_UP)
done = False # loop control
timer = Event()
def quit_loop(): # Called by inbuilt threaded interrupt
global done
done = True
timer.set() # Interrupt the waiting
GPIO.add_event_detect(GPIO_ONOFF, GPIO.FALLING, callback=quit_loop, bouncetime=300) # Setup interrupt to call quit_loop
Because you're using this to break out of a loop, you want to shorten that loop to a single process:
tasks = [
(GPIO_nek, GPIO.LOW, interval1),
(GPIO_schouder, GPIO.LOW, interval1),
(GPIO_nek, GPIO.HIGH, interval1),
(GPIO_rug1, GPIO.LOW, interval2),
(GPIO_schouder, GPIO.HIGH, 0) ]
for pin, level, interval in tasks * 20: # Above you ran it 20 times, this notation keeps it in a single loop to break our o
if not done:
GPIO.digitalWrite(pin, level)
timer.wait(interval)
else:
timer.clear()
break
By using the threading Event().wait() and .set() instead of the standard time.sleep() you won't even have to wait for the sleep interval to finish.
I am trying to create a program that runs an infinite loop in parallel and exits the loops when it is told too. Specifically, the infinite loop is in the square function and the exiting signal is given when shv='STOP'. When all processes read that signal will have to exit the infinite loop and return.
The problem is that the Processes do not close even after giving the STOP signal.
Some notes:
As many instances of multiprocessing code, this code runs in the terminal rather than in IDEs.
The code:
import multiprocessing as mp
import time
import ctypes
def square(x, shv):
while shv.value != 'STOP':
time.sleep(3)
print(shv.value)
else:
print('stopped')
return
if __name__ == '__main__':
stopphrase = 'STOP'
proecess_num = 2
shv = mp.Value(ctypes.c_wchar_p, '')
processes = [mp.Process(target=square, args=(i, shv)) for i in range(proecess_num)]
for p in processes:
p.start()
print('Mapped & Started')
print(processes)
while shv.value != stopphrase:
inp = input('Type STOP and press Enter to terminate: ')
if inp == stopphrase:
shv.value = stopphrase
time.sleep(2)
p.terminate()
print(processes)
For some reason this code gives the following in both cases of print(processes) even though I set the shv.value = stopphrase:
[<Process name='Process-1' pid=9664 parent=6084 started>, <Process name='Process -2' pid=10052 parent=6084 started>]
Please let me know for further improvements or details of the question.
I think you meant to have a loop calling ‘join()’ on each process.
for p in processes:
p.join()
instead of calling terminate on just one of them.