# Searches for the first five perfect numbers. # This version uses a multi-process pool for concurrency. import itertools import math # for sqrt import os import time from multiprocessing import Pool # returns the sum of the proper divisors of n def sum_divisors(n): root = int(math.sqrt(n)) result = sum((k + n // k for k in range(2, root + 1) if n % k == 0)) + 1 if n == root * root: result -= root return result # returns n if n is a perfect number, else None def is_perfect_number(n): if n == sum_divisors(n): return n # Runs the given function f, measuring how long it took to run. # Returns the elapsed runtime at the end of the call. def measure_runtime(f): start_time = time.time() f() elapsed_time = time.time() - start_time return elapsed_time # Finds and prints the first 5 perfect numbers. def find_perfect_numbers(): print("Searching for perfect numbers on", os.cpu_count(), "CPUs") nums = range(1, 200001) # itertools.count(1) pool = Pool() divs = pool.imap(is_perfect_number, nums) perfects = (n for n in divs if n is not None) first_five = itertools.islice(perfects, 5) for k in first_five: print(k) print("Done") def main(): runtime = measure_runtime(find_perfect_numbers) print("time =", runtime, "sec") main() def fake_range(start, stop): for i in range(start, stop+1): if i < 100000 or i > 30550300: # if i % 1000 == 0: # print(" -- fake_range yielding", i) yield i def fake_slice(itr, stop): for i in range(stop): val = next(itr) yield val