I'm quite new to Python threading, and still can't make it working properly. I do not understand why, but threads are executed consequently and not in a parallel.
Could anyone please advice, what is incorrect in the code (I simplified it as much as I can to get it closer to the examples, but it doesn't work as expected):
import threading, time
def func1():
for j in range (0, 10):
print(str(time.ctime(time.time())) + " 1")
time.sleep(0.5)
def func2():
for j in range (0, 10):
print(str(time.ctime(time.time())) + " 2")
time.sleep(0.5)
print(str(time.ctime(time.time())) + " script started")
t1 = threading.Thread(target = func1(), name = " 1")
t2 = threading.Thread(target = func2(), name = " 2")
t1.start()
t2.start()
t1.join()
t2.join()
print (str(time.ctime(time.time())) + " over")
In console output I see that the second thread only starts when the first one is finished. I've tried to make threads daemonic, remove .join() lines, but still no luck.
I want to indicate the fact that a threading.Lock object and condition synchronization objects they define are used with the "with statement," because they support the context management protocol:
lock = threading.Lock() # After: import threading
with lock:
# critical section of code
...access shared resources...
Here, the context management machinery guarantees that the lock is automatically acquired before the block is executed and released once the block is complete, regardless of exception outcomes.
Therefore, the suggested solution above by Vincent seems to be addressing a more complex problem, one that deals with placing a lock on shared common resources, stopping any other thread that tries to access the resource in its tracks (in fact, stopping any thread that attempts to acquire the same lock). Notes: A threading.Lock has two states: locked and unlocked, and it is created in the unlocked state. In the following, for example, as only one thread can update the global variable "count":
import threading, time
count = 0
def adder(addlock): # shared lock object passed in
global count
with addlock:
count = count + 1 # auto acquire/release around stmt
time.sleep(0.5)
with addlock:
count = count + 1 # only 1 thread updating at any time
addlock = threading.Lock()
threads = []
for i in range(100):
thread = threading.Thread(target=adder, args=(addlock,))
thread.start()
threads.append(thread)
for thread in threads: thread.join()
print(count)
I'd suggest another solution using multiprocessing since your two parallel functions are basically two separate processes that don't need to access any shared resources.
from multiprocessing import Process
import time
def func1():
for j in range (0, 10):
print(str(time.ctime(time.time())) + " 1")
time.sleep(0.5)
def func2():
for j in range (0, 10):
print(str(time.ctime(time.time())) + " 2")
time.sleep(0.5)
if __name__ == '__main__':
print(str(time.ctime(time.time())) + " script started")
p1 = Process(target=func1)
p1.start()
p2 = Process(target=func2)
p2.start()
p1.join()
p2.join()
print (str(time.ctime(time.time())) + " over")
You're calling your targets (target=func1()). Instead do as follows:
t1 = threading.Thread(target=func1, name = "1")
t2 = threading.Thread(target=func2, name = "2")
EDIT: This is how you lock your prints :
import threading, time
def func1(lock):
for j in range (10):
with lock:
print(str(time.ctime(time.time())) + " 1")
time.sleep(0.5)
def func2(lock):
for j in range (10):
with lock:
print(str(time.ctime(time.time())) + " 2")
time.sleep(0.5)
lock = threading.Lock()
t1 = threading.Thread(target = func1, name = " 1", args=(lock,))
t2 = threading.Thread(target = func2, name = " 2", args=(lock,))
Related
"Write a program using two threads such that one writes even numbers in increasing order and the other odd numbers in incresing order with respect to a certain threashold."
For instance, given 10 I would like to have as output
T1-0
T2-1
T1-2
T2-3
...
T1-8
T2-9
I think an event object should be used in order to alternate between the print of a thread with the other, but I do not know how to implement it in order to make it work, since I think I have not fully grasped the tools to work with threads, yet. I leave here my faulty code for the task
import threading
e = threading.Event()
def even(n):
if e.isSet() == False:
for i in range(0,n,+2):
e.set()
print(i)
e.clear()
e.wait()
def odd(n):
for i in range(1,n,+2):
e.wait()
print(i)
e.set()
t1 = threading.Thread(target = odd, args=(10,))
t2 = threading.Thread(target = even, args=(10,))
t1.start()
t2.start()
t1.join()
t2.join()
import threading
import time
def thread_function(name,max,y):
print(name,y)
time.sleep(0.1)
for i in range(int(max/2)):
time.sleep(0.3)
y= y + 2
print(name,y)
n = input("Input an integer \n")
n = int(n)
p=0
# Create thread
mt1 = threading.Thread(target=thread_function, args=("T-Even",n,p))
mt2 = threading.Thread(target=thread_function, args=("T-Odd",n,p+1))
# Start thread
mt1.start()
time.sleep(0.1)
mt2.start()
mt1.join()
I have made a thread that is supposed to show the seconds passing. Unfortunately, when I use getstr from the curses module the whole script stops, including the thread. I have to use a thread lock to stop random characters being printed out because of overlapping orders.
Any suggestions on how to fix this or an alternative would be great!
In the below example window and window2 are already set-up...
lock = threaing.Lock()
def main_function():
#starts thread
t1 = threading.Thread(target=time_calc,args=(window2,))
t1.start()
#Gets user input
while True:
data = window1.addstr(y,x,"Type something in!")
data = window1.getstr(y,x,5)
lock.acquire()
window1.erase()
txt = "You said: "+data
window1.addstr(y,x,txt)
lock.release()
def time_calc(window2):
current_count = 0
while True:
time += 1
text = "Time Count: "+str(time)
lock.acquire()
window2.erase()
window2.addstr(y,x,text)
lock.release()
time.sleep(1)
The problem with my code
I figured out the problem with my code. You can't run a thread inside a thread for some reason and I originally had my main function called to be considered a thread. I guess I should have stated this in my question. Sorry
There is probably a way to run a thread in a thread, but this did not work for me.
My Updated Code
lock = threading.Lock()
def call_threads():
t1 = threading.Thread(target=main_function,args=(window1,))
t1.start()
t2 = threading.Thread(target=time_calc,args=(window2,))
t1.start()
def main_function(window1):
#Gets user input
while True:
data = window1.addstr(y,x,"Type something in!")
data = window1.getstr(y,x,5)
lock.acquire()
window1.erase()
txt = "You said: "+data
window1.addstr(y,x,txt)
lock.release()
def time_calc(window2):
current_count = 0
while True:
time += 1
text = "Time Count: "+str(time)
lock.acquire()
window2.erase()
window2.addstr(y,x,text)
lock.release()
time.sleep(1)
If there is anything else that may have caused this error, please comment it!
I am working on a Python scripts that kicks off a thread with a loop and a raw_input so that user can enter commands. After this thread starts, main program starts a loop with another raw_input so that the user can enter commands.
How can this be organized so that the commands being inputted via console goes to the correct raw_input (main thread/concurrent thread)? At the moment, all inputs in the console are going to the main thread only.
Thanks
Example
import threading
def commThread():
while True:
chatAcceptance = raw_input("User")
t1 = threading.Thread(target=commThread)
t1.start()
while True:
userInput = raw_input("\nPlease insert a command:\n")
So this can be done via lock. I did a small code example that shows how to swap between one "scope" to the other using the raw_input.
import threading
lock = threading.Lock()
def inputReader(thread, prompt):
userInput = raw_input(prompt)
print thread + " " + userInput + "\n"
return userInput
def myThread1():
global lock
while True:
lock.acquire()
print "thread 1 got the lock\n"
while True:
threadInput = inputReader("thread 1", "from thread 1\n")
if threadInput == "release":
lock.release()
print "thread 1 released the lock\n"
break
def myThread2():
global lock
while True:
lock.acquire()
print "thread 2 got the lock\n"
while True:
threadInput = inputReader("thread 2", "from thread 2\n")
if threadInput == "release":
lock.release()
print "thread 2 released the lock\n"
break
t1 = threading.Thread(target=myThread1).start()
t2 = threading.Thread(target=myThread2).start()
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've made a python script that factorizes a number into its prime factors. However when dealing with big numbers i may like to have an idea to the progress of the computation. (I simplified the script)
import time, sys, threading
num = int(input("Input the number to factor: "))
factors = []
def check_progress():
but = input("Press p: ")
if but == "p":
tot = int(num**(1/2))
print("Step ", k, " of ", tot, " -- ", round(k*100/tot,5), "%", end="\r", sep="")
t = threading.Thread(target=check_progress) ?
t.daemon = True ?
t.start() ?
k = 1
while(k != int(num**(1/2))):
k = (k+1)
if num%k == 0:
factors.append(int(k))
num = num//k
k = 1
print(factors)
I'm wondering if there is a way to show the progress on demand, for example, during the loop, i press a key and it prints the progress?
How can i implement a thread of something like that in my script?
Thanks and sorry for my english
Edit:
def check_progress():
while True:
but = input("## Press return to show progress ##")
tot = int(num**(1/2))
print("Step ", k, " of ", tot, " -- ", round(k*100/tot,5), "%", sep="")
Here is one possible design:
Main thread:
create queue and thread
start the progress thread
wait user input
on input:
pop result from queue (may be None)
display it
loop
Progress thread:
do the work an put status in queue
I can provide example, but I feel you are willing to learn. Feel free to comment for help.
Edit: Full example with queue.
from time import sleep
from Queue import Queue
from threading import Thread
# Main thread:
def main():
# create queue and thread
queue = Queue()
thread = Thread(target=worker, args=(queue,))
# start the progress thread
thread.start()
# wait user input
while thread.isAlive():
raw_input('--- Press any key to show status ---')
# pop result from queue (may be None)
status = queue.get_nowait()
queue.task_done()
# display it
if status:
print 'Progress: %s%%' % status
else:
print 'No status available'
# Progress thread:
def worker(queue):
# do the work an put status in queue
# Simulate long work ...
for x in xrange(100):
# put status in queue
queue.put_nowait(x)
sleep(.5)
if __name__ == '__main__':
main()