How come more threads worsens the perfomance? - multithreading

The following code gets 2 numbers from the user and calculates how many primes are there between those numbers.
Running the code (between 1 and 1000000) without threads got me 2.8 secs and with 2 threads (my CPU has 2 cores) I got 4.8 secs.
Is it a problem with the PC, the code.
If you could try and run it on your PC and share the results i would thank you for that.
If you see a problem with the code or have any idea why that happens share your toughts.
import math
from threading import Thread
from timeit import timeit
first_num = input()
last_num = input()
primes = []
def is_prime(num):
if num == 2:
return True
if num == 1 or num % 2 == 0:
return False
for i in xrange(3, int(math.sqrt(num)) + 1, 2):
if (num % i == 0):
return False
return True
def find_primes(numbers):
for num in numbers:
if is_prime(num):
primes.append(num)
def targil_a():
find_primes(xrange(first_num, last_num))
print len(primes)
def targil_b():
numbers = range(first_num, last_num)
threads = []
for i in xrange(2):
part_len = int(len(numbers)/2)
t = Thread(target=find_primes, args=(numbers[part_len*i: part_len*(i+1) + 1],))
t.start()
threads.append(t)
for trd in threads:
trd.join()
print len(primes)
print timeit(targil_a, number=1)
primes = []
print timeit(targil_b, number=1)

Related

Why is my simple code taking so much time to execute when i give in large numbers as input?

I have written a simple code to print the largest prime factor of a given number from Project Euler. It works just fine for numbers like 24, but there is no response from the python shell for large numbers!
a=600851475143
b=[]
for i in range(2,600851475143):
if a%i==0:
if i==2:
b.append(i)
continue
for j in range(2,i+1):
if j==i:
b.append(i)
if i%j==0:
break
print(max(b))
print(b)
You can use an algorithm like this to get large factors of prime numbers:
import math
def LLL(N):
p = 1<<N.bit_length()-1
if N == 2:
return 2
if N == 3:
return 3
s = 4
M = pow(p, 2) - 1
for x in range (1, 100000):
s = (((s * N ) - 2 )) % M
xx = [math.gcd(s, N)] + [math.gcd(s*p+x,N) for x in range(7)] + [math.gcd(s*p-x,N) for x in range(1,7)]
try:
prime = min(list(filter(lambda x: x not in set([1]),xx)))
except:
prime = 1
if prime == 1:
continue
else:
break
return N/prime

Can any one help me with this one . I was trying to write a prog for finding 'LCM'. I want to equate these variable

Here c and d basically represent tables of respective number for variable a and b...i am trying to match the least common product from these table.Please help me figure it out
a=(input('your first no: '))
b=(input('your second no: '))
for i in range(1,100):
c=a*i
d=b*i
if (c==d):
print('lcm is')
Here is a program that will work. It will also calculate the LCM of more than two numbers.
from collections import Counter
from operator import mul
from functools import reduce
def primeFactors(n):
if not isinstance(n, int) or n < 1:
raise ValueError("must be positive integer")
factors = []
while n % 2 == 0:
factors.append(2)
n /= 2
i = 3
while n != 1:
while n % i == 0:
factors.append(i)
n /= i
i += 2
return factors
def get_lcm(numbers):
factorisations = [Counter(primeFactors(n)) for n in numbers]
primes = frozenset().union(*(set(x.keys()) for x in factorisations))
primes_to_max_powers = (p ** max(*(x.get(p,0) for x in factorisations))
for p in primes)
return reduce(mul, primes_to_max_powers, 1)
a = int(input('your first no: '))
b = int(input('your second no: '))
print('lcm is', get_lcm([a, b]))
Or you can do this instead but it might be a bit slower:
a = input('your first no: ')
b = input('your second no: ')
for i in range(max(a, b), a * b + 1):
if i % a == 0 and i % b == 0:
lcm = i
break
print('lcm is ', lcm)
Use the formula lcm(a,b) = a⋅b / gcd(a,b). Python has a gcd function in the standard library:
from fractions import gcd
def least_common_multiple(a, b):
return a * b / gcd(a, b)
Since Python 3.6, it's arguably preferable to use the gcd builtin from math:
try:
from math import gcd
except ImportError:
from fractions import gcd
def least_common_multiple(a, b):
return a * b / gcd(a, b)

Co-routine returns None for every alternate iteration

I have a piece of code as shown below:
#!/bin/python3
import math
import os
import random
import re
import sys
import logging
def consumer():
while True:
x = yield
print(x)
def producer(n):
for _ in range(n):
x = int(input())
yield x
def rooter():
logging.info("Running the rooter")
while True:
value = (yield)
yield math.sqrt(value)
def squarer():
logging.info("Running the squarer")
while True:
value = (yield)
print("from squarer: {}".format(value))
yield value * value
def accumulator():
logging.info("Running the accumulator.")
running_total = 0
while True:
value = (yield)
running_total += value
yield running_total
def pipeline(prod, workers, cons):
logging.info("workers: {}".format(workers))
for num in prod:
for i, w in enumerate(workers):
num = w.send(num)
cons.send(num)
for worker in workers:
worker.close()
cons.close()
if __name__ == '__main__':
order = input().strip()
m = int(input())
prod = producer(m)
cons = consumer()
next(cons)
root = rooter()
next(root)
accumulate = accumulator()
next(accumulate)
square = squarer()
next(square)
pipeline(prod, eval(order), cons)
Sample input
[square, accumulate]
3 <- Number of inputs coming further
1 <- actual inputs
2
3
Sample Output
*The output should be as below:*
1
5
14
but comes to
10(sum of the squares of 1 and 3) when it should actually be 14 (sum of the squares of 1, 2, 3)
So essentially the input 2 is missed (It's second in the line of inputs).
On debugging further I found that this is the case for every alternate iteration, not just for the provided inputs here.
I am not able to decipher what's happening. If it's of any help, the co-routine squarer is the one returning None in the second iteration.
I'd appreciate any help.
I found a solution to this.
It's that we prime the co-routine after use in the pipeline function so the code becomes as follows: I have marked the next(w) line within asterix for reference.
#!/bin/python3
import math
import os
import random
import re
import sys
import logging
def consumer():
while True:
x = yield
print(x)
def producer(n):
for _ in range(n):
x = int(input())
yield x
def rooter():
logging.info("Running the rooter")
while True:
value = (yield)
yield math.sqrt(value)
def squarer():
logging.info("Running the squarer")
while True:
value = (yield)
print("from squarer: {}".format(value))
yield value * value
def accumulator():
logging.info("Running the accumulator.")
running_total = 0
while True:
value = (yield)
running_total += value
yield running_total
def pipeline(prod, workers, cons):
logging.info("workers: {}".format(workers))
for num in prod:
for i, w in enumerate(workers):
num = w.send(num)
**next(w)**
cons.send(num)
for worker in workers:
worker.close()
cons.close()
if __name__ == '__main__':
order = input().strip()
m = int(input())
prod = producer(m)
cons = consumer()
next(cons)
root = rooter()
next(root)
accumulate = accumulator()
next(accumulate)
square = squarer()
next(square)
pipeline(prod, eval(order), cons)
As mentioned in PEP specification it says that a generator function's yield
is always None when resumed by a normal next call. So when explicitly made to yield, it'll be ready to handle the next input immediately in this case.

Python: Roll a dice for 12 times, calculate the probability if each number equally shows up twice

I've drafted the below code for the captioned question, but the return result is always 0. Could anyone please help me figure out what's the problem here?
Thanks a lot!
import random
dice_sides = 6
frequency_list = []
def roll_dice(times):
results = []
for roll_num in range(times):
result = random.randint(1,dice_sides)
results.append(result)
for i in range(dice_sides):
if results.count(i) != 2:
frequency = 0
break
else:
frequency = 1
return frequency
def occurrence(N,times):
for j in range(N):
frequency_list.append(roll_dice(times))
prob = frequency_list.count(1)
return prob
print(occurrence(10000,12))
You can try something like this
Code
import random
from collections import Counter
def roll_dice(n_sides, times):
if n_sides % times:
return 0
results = []
for roll_num in range(times):
result = random.randint(1, n_sides)
results.append(result)
# I'm using set here and will check its length,
# Counter(results) returns a dict of items (item, count)
# and if every item has the same count it should have length 1.
# More generic statement not only for (2 in this case)
res_dict = set(Counter(results).values())
if len(res_dict) == 1:
return 1
return 0
def mean(ar):
return sum(ar)/len(ar)
def occurrence(N, n_sides, times):
frequency_list = []
for j in range(N):
frequency_list.append(roll_dice(n_sides, times))
prob = mean(frequency_list)
return prob
if __name__ == '__main__':
N = 100000 # I intentionally made it 100k
n_sides = 6
times = 12
res_prob = occurrence(N, times)
print(res_prob)
Output
0.00604
[Finished in 3.6s]

Euler 12 need optimization

I have solved euler problem 12, but it needs some optimization. I have read on the euler forums, but it has not helped me optimized it. However, I have managed to get the solution, I just need to speed it up. It currently takes 4 minutes to run. Here is my code:
import time
def nthtriangle(n):
return (n * (n + 1)) / 2
def numberofnfactors(n):
count = 0
if n==1:
return 1
for i in range(1, 1 + int(n ** 0.5)):
if n % i == 0:
count += 2
return count
def FirstTriangleNumberWithoverxdivisors(divisors):
found = False
counter = 1
while not found:
print(int(nthtriangle(counter)), " ", numberofnfactors(nthtriangle(counter)))
if numberofnfactors(nthtriangle(counter)) > divisors:
print(" first triangle with over ",divisors, " divisors is ", int(nthtriangle(counter)))
found = True
break
counter += 1
start_time = time.time()
FirstTriangleNumberWithoverxdivisors(500)
print("My program took", time.time() - start_time, "to run")
Instead of calculating each triangle number individually, use a generator to get the triangle numbers
from timeit import timeit
def triangle_numbers():
count = 1
num = 0
while True:
num += count
count += 1
yield num
def count_divisors(n):
count = 0
if n==1:
return 1
for i in range(1, 1 + int(n ** 0.5)):
if n % i == 0:
count += 2
return count
print(timeit('next(num for num in triangle_numbers() if count_divisors(num) >= 500)',
globals=globals(), number=1))
Gives me 3.8404819999996107 (seconds) on my machine. You could probably also improve the divisor counting.
What's really slowing you down is calling nthtriangle and numberoffactors more than once in your loop! Plus, those calls to print aren't free.

Resources