I have to test if n = 17 is a prime number: (n-1)! mod n = n-1. For that first I have to calculate the factorial of 16 through 4 threads, that means that the interval 1..16 has to be divided in 4 sub-intervals: 1..4, 5..8, 9..12, 14..16. I have managed to test if 17 is a prime number through 16 threads, one for each operation, but I don’t know how I could sub-divide it so that the operations are done in only 4 threads.
I would very much appreciate some ideas, thank you!
Here is my code:
import threading
n = 17
t = n-1
ts = []
num = (n-1)/t
def calcFak():
for i in range(t):
c = i*(n-1)/t+1
thread = threading.Thread(target=threads, args = (c,))
ts.append(thread)
thread.start()
thread.join()
def threads(var):
print(f"start thread {var}")
global num
num = num * var
print(f"end thread {var}")
def managerThread(thread):
calcFak()
print(num)
if num % n == t:
print(n, ' is Prime')
else:
print(n, ' is not Prime')
t2 = threading.Thread(target = managerThread, args=(ts,))
t2.start()
Right now you are calculating everything sequentially because of the thread join() statement in your calcFak() function. Thus, the execution of your function right now is actually the same as the code below:
n = 17
t = n - 1
num = t/t
for i in range(t):
c = i*t/t + 1
print(f'Start {c}')
num = num * c
print(f'End thread {c}')
print(num)
if num % n == t:
print(f'{n} is a prime number')
else:
print(f'{n} is not a prime number')
As you can see, no threading benefit. Instead, use queues and worker functions to subdivide your program's execution:
import threading
from queue import Queue
import time
n = 17
t = n - 1
num = t/t
# For threading
q = Queue()
num_lock = threading.Lock() # Lock so that no threads can overwrite our num value
threads = [] # List to store created threads
# Our worker gets items from the queue and processes them
def worker():
global num
while True:
if not q.empty():
c = q.get()
num_lock.acquire()
num = num * c
num_lock.release()
q.task_done()
for i in range(t):
q.put(i*t/t + 1)
for thread in range(4):
threads.append(threading.Thread(target=worker))
threads[-1].daemon = True
threads[-1].start()
print('Made 1 thread')
q.join()
if num % n == t:
print(f'{n} is a prime number')
else:
print(f'{n} is not a prime number')
# Prints:
# Made 1 thread
# Made 1 thread
# Made 1 thread
# Made 1 thread
# 17 is a prime number
In the code above, we create a queue that holds data for the worker functions to use. The worker functions get a lock on the num variable, and then modify it. Once the queue is empty (which happens after we join the queue with q.join()) we then access the final value of the num variable to determine if the number is prime or not.
Related
I'm trying to run this program but it is showing me "Thread 0 has 0 prime numbers" in the console followed by "Killed" after 5 minutes. Moreover, it is very slow. Please help me develop and correct this code.
import time
Nthreads=4
maxNumber=3000000
starting_range=0
ending_range=0
division=0
lst=[]
def prime(x, y):
prime_list = []
for i in range(x, y):
if i == 0 or i == 1:
continue
else:
for j in range(2, int(i/2)+1):
if i % j == 0:
break
else:
prime_list.append(i)
return prime_list
def func_thread(x, y):
out.append(prime(x, y))
thread_list = []
results = len(lst)
for i in range(Nthreads):
devision=maxNumber//Nthreads
starting_range = (i-1)*division+1
ending_range = i*devision
lst = prime(starting_range, ending_range)
print(" Thread ", i, " has ", len(lst), " prime numbers." )
thread = threading.Thread(target=func_thread, args=(i, results))
thread_list.append(thread)
for thread in thread_list:
thread.start()
for thread in thread_list:
thread.join()```
In Python, if you use multithreading for CPU-bound tasks, it will be slower than if you don't use multithreading. You need to use multiprocessing for this problem. You can read this article for more informations: https://www.geeksforgeeks.org/difference-between-multithreading-vs-multiprocessing-in-python/
Multithreading is wholly inappropriate for CPU-intensive work such as this. However, it can be done:
from concurrent.futures import ThreadPoolExecutor
NTHREADS = 4
MAXNUMBER = 3_000_000
CHUNK = MAXNUMBER // NTHREADS
assert MAXNUMBER % NTHREADS == 0
RANGES = [(base, base+CHUNK) for base in range(0, MAXNUMBER, CHUNK)]
all_primes = []
def isprime(n):
if n <= 3:
return n > 1
if not n % 2 or not n % 3:
return False
for i in range(5, int(n**0.5)+1, 6):
if not n % i or not n % (i + 2):
return False
return True
def process(_range):
lo, hi = _range
if lo < 3:
all_primes.append(2)
lo = 3
elif lo % 2 == 0:
lo += 1
for p in range(lo, hi, 2):
if isprime(p):
all_primes.append(p)
with ThreadPoolExecutor() as executor:
executor.map(process, RANGES)
The all_primes list is unordered. Note also that this strategy will only work if MAXNUMBER is exactly divisible by NTHREADS.
Note on performance:
This takes 7.88s on my machine. A multiprocessing variant takes 2.90s
This question already has answers here:
Is there any way to kill a Thread?
(31 answers)
Closed 12 months ago.
I search a way to transform this kind of code from multiprocessing into multithreading:
import multiprocessing
import random
import time
FIND = 50
MAX_COUNT = 100000
INTERVAL = range(10)
queue = multiprocessing.Queue(maxsize=1)
def find(process, initial):
succ = False
while succ == False:
start=initial
while(start <= MAX_COUNT):
if(FIND == start):
queue.put(f"Found: {process}, start: {initial}")
break;
i = random.choice(INTERVAL)
start = start + i
print(process, start)
processes = []
manager = multiprocessing.Manager()
for i in range(5):
process = multiprocessing.Process(target=find, args=(f'computer_{i}', i))
processes.append(process)
process.start()
ret = queue.get()
for i in range(5):
process = processes[i]
process.terminate()
print(f'terminated {i}')
print(ret)
The way it works is it starts multiple processes and after the first process finished the function find isn't needed anymore. I tried to transform it in that way, but unfortunately the terminate function is not usable:
import _thread as thread
import queue
import random
import time
FIND = 50
MAX_COUNT = 100000
INTERVAL = range(10)
qu = queue.Queue(maxsize=1)
def find(process, initial):
succ = False
while succ == False:
start=initial
while(start <= MAX_COUNT):
if(FIND == start):
qu.put(f"Found: {process}, start: {initial}")
break;
i = random.choice(INTERVAL)
start = start + i
print(process, start)
threads = []
for i in range(5):
th = thread.start_new_thread(find, (f'computer_{i}', i))
threads.append(th)
ret = qu.get()
for i in range(5):
th = threads[i]
th.terminate()
print(f'terminated {i}')
print(ret)
How can I get some termination of threads?
Try:
for id, thread in threading._active.items():
types.pythonapi.PyThreadState_SetAsyncExc(id, ctypes.py_object(SystemExit))
I create multiple sub functions to process data and want to return the main function, once any nested function meets some condition. Then, the multiprocessing can continue the processes.
Here's a simple example:
import multiprocessing
from multiprocessing import Pool
def program1(num):
num += 1
return num
def program2(num):
num += 1
return num
def program3(num):
num += 1
return num
def main(num):
num = program1(num)
if num %2 != 0:
return
else:
num = program2(num)
if num %3 != 0:
return
else:
num = program3(num)
print(num)
return num
pool = Pool(4)
nums = range(8)
pool.map(main, nums)
Because there're multiple programs, it will make the code looks quite long ...
Is it possible to wrap the if condition in each nested function?
Then I can just use
def main(num):
num = program1(num)
num = program2(num)
num = program3(num)
Note that please don't care or simplify the data process hah. This is just an example to show the processes.
I am trying to use the ProcessPoolExecutor() to run some functions but I cant manage to understand how to get the return of the functions out of the with.
def threaded_upload(i):
time.sleep(2)
if i == 0:
k = 10
elif i == 2:
k = i*i
else:
k = -99
return [k]
def controller():
if __name__ == "__main__":
futures = []
with ProcessPoolExecutor() as pool:
for paso in range(4):
futuro_i = pool.submit(threaded_upload,paso)
wth=[futuro_i.result()]
futures.append(futuro_i)
wait(futures, return_when=ALL_COMPLETED)
merged_list = []
for future in futures:
for valor in future.result():
merged_list.append(valor)
Lista_Final = merged_list
wait(futures, return_when=ALL_COMPLETED)
return Lista_Final
print(controller())
The output of the code is:
None
[10, -99, 4, -99]
I am not sure why?
The "wait" doesn't seem to wait until all functions are executed either.
To be honest, I have been reading and reading for a few days but the description of concurrent.futures or multiprocessing are more advanced that my current knowledge.
Any clarification will be appreciated.
Thanks in advance.
You first submit the jobs and then wait for the results. You can also return an integer instead of a list and then skip the inner loop:
test.py:
import random
import time
from concurrent.futures import ProcessPoolExecutor, wait
def worker(i):
t = random.uniform(1, 5)
print(f"START: {i} ({t:.3f}s)")
time.sleep(t)
if i == 0:
k = 10
elif i == 2:
k = i * i
else:
k = -99
print(f"END: {i}")
return k
def main():
futures = []
with ProcessPoolExecutor() as pool:
for i in range(4):
future = pool.submit(worker, i)
futures.append(future)
results = []
done, pending = wait(futures) # ALL_COMPLETED is the default value
for future in done:
results.append(future.result())
print(results)
if __name__ == "__main__":
main()
Test:
$ python test.py
START: 0 (1.608s)
START: 1 (1.718s)
START: 2 (1.545s)
START: 3 (1.588s)
END: 2
END: 3
END: 0
END: 1
[10, -99, 4, -99]
I am trying to create a program that takes in 2 numbers from the user and use a different thread to test each one, this is what i have so far and i know i am a good bit off but i find this threading stuff very difficult
#!/usr/bin/python
import threading
class PrimeNumber(threading.Thread):
def __init__(self, number):
threading.Thread.__init__(self)
self.Number = number
def run(self):
counter = 2
while counter*counter < self.Number:
if self.Number % counter == 0:
print "%d is no prime number, because %d = %d * %d" % ( self.Number, self.Number, counter, self.Number / counter)
return
counter += 1
print "%d is a prime number" % self.Number
threads = []
while True:
input1 = long(raw_input("Enter first number: "))
if input < 1:
break
thread1 = PrimeNumber(input1)
threads += [thread1]
thread1.start()
input2 = long(raw_input("Enter second number: "))
if input < 1:
break
thread2 = PrimeNumber(input2)
threads += [thread2]
thread2.start()
for x in threads:
x.join()
I made a few modifications to your code.
The second input needed a while loop as well. break doesn't make sense outside of a loop.
I flipped both cases where you had input1 < 1 to input1 > 1 because you want to quit the loop when you have a valid input, not when you have an invalid input.
I indented the code in the first while loop correctly.
I moved the <thread>.start lines to the for loop.
This is what it looks like now:
import threading
class PrimeNumber(threading.Thread):
def __init__(self, number):
threading.Thread.__init__(self)
self.Number = number
def run(self):
counter = 2
while counter*counter < self.Number:
if self.Number % counter == 0:
print "%d is not a prime number, because %d = %d * %d" % ( self.Number, self.Number, counter, self.Number / counter)
return
counter += 1
print "%d is a prime number" % self.Number
threads = []
while True:
input1 = long(raw_input("Enter first number: "))
if input1 > 1:
break
thread1 = PrimeNumber(input1)
threads += [thread1]
while True:
input2 = long(raw_input("Enter second number: "))
if input2 > 1:
break
thread2 = PrimeNumber(input2)
threads += [thread2]
for x in threads:
x.start()
x.join()
You said in your question title that you want to check five numbers. Instead of duplicating that particular section of code where you get input and make a thread for it three more times, put it in a for loop, like so:
threads = []
for i in range(5):
while True:
inputNum = long(raw_input("Enter first number: "))
if inputNum > 1:
break
thread = PrimeNumber(inputNum)
threads += [thread]