Skip to content

Commit 5b6657e

Browse files
committed
Chapter 17
1 parent 2b164c5 commit 5b6657e

5 files changed

Lines changed: 330 additions & 0 deletions

File tree

Ch17/collatz_multi.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import concurrent.futures
2+
3+
BOUND = 10**6
4+
5+
6+
def collatz(n):
7+
steps = 0
8+
while n > 1:
9+
if n % 2:
10+
n = n * 3 + 1
11+
else:
12+
n = n // 2
13+
steps += 1
14+
return steps
15+
16+
17+
def length_counter(target):
18+
count = 0
19+
with concurrent.futures.ProcessPoolExecutor() as executor:
20+
for result in executor.map(
21+
collatz,
22+
range(2, BOUND),
23+
chunksize=BOUND//4
24+
):
25+
if result == target:
26+
count += 1
27+
return count
28+
29+
30+
def get_input(prompt):
31+
while True:
32+
n = input(prompt)
33+
try:
34+
n = int(n)
35+
except ValueError:
36+
print("Value must be an integer.")
37+
continue
38+
39+
if n <= 0:
40+
print("Value must be positive.")
41+
else:
42+
return n
43+
44+
45+
def main():
46+
print("Collatz Sequence Counter")
47+
48+
target = get_input("Collatz sequence length to search for: ")
49+
print(f"Searching in range 1-{BOUND}...")
50+
51+
with concurrent.futures.ThreadPoolExecutor() as executor:
52+
future_guess = executor.submit(
53+
get_input,
54+
"How many times do you think it will appear? "
55+
)
56+
57+
count = length_counter(target)
58+
59+
guess = future_guess.result()
60+
61+
if guess == count:
62+
print("Exactly right! I'm amazed.")
63+
elif abs(guess - count) < 100:
64+
print(f"You're close! It was {count}.")
65+
else:
66+
print(f"Nope. It was {count}.")
67+
68+
69+
if __name__ == "__main__":
70+
main()

Ch17/collatz_pool.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import concurrent.futures
2+
3+
BOUND = 10**5
4+
5+
6+
def collatz(n):
7+
steps = 0
8+
while n > 1:
9+
if n % 2:
10+
n = n * 3 + 1
11+
else:
12+
n = n // 2
13+
steps += 1
14+
return steps
15+
16+
17+
def length_counter(target):
18+
count = 0
19+
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
20+
for result in executor.map(collatz, range(2, BOUND)):
21+
if result == target:
22+
count += 1
23+
return count
24+
25+
26+
def get_input(prompt):
27+
while True:
28+
n = input(prompt)
29+
try:
30+
n = int(n)
31+
except ValueError:
32+
print("Value must be an integer.")
33+
continue
34+
35+
if n <= 0:
36+
print("Value must be positive.")
37+
else:
38+
return n
39+
40+
41+
def main():
42+
print("Collatz Sequence Counter")
43+
44+
target = get_input("Collatz sequence length to search for: ")
45+
print(f"Searching in range 1-{BOUND}...")
46+
47+
with concurrent.futures.ThreadPoolExecutor() as executor:
48+
future_guess = executor.submit(
49+
get_input,
50+
"How many times do you think it will appear? "
51+
)
52+
53+
count = length_counter(target)
54+
55+
guess = future_guess.result()
56+
57+
if guess == count:
58+
print("Exactly right! I'm amazed.")
59+
elif abs(guess - count) < 100:
60+
print(f"You're close! It was {count}.")
61+
else:
62+
print(f"Nope. It was {count}.")
63+
64+
65+
if __name__ == "__main__":
66+
main()

Ch17/collatz_producer_consumer.py

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
import concurrent.futures
2+
import multiprocessing
3+
import queue
4+
import itertools
5+
import signal
6+
import time
7+
8+
BOUND = 10**5
9+
10+
in_queue = multiprocessing.Queue(100)
11+
exit_event = multiprocessing.Event()
12+
13+
14+
def exit_handler(signum, frame):
15+
exit_event.set()
16+
17+
18+
signal.signal(signal.SIGINT, exit_handler)
19+
signal.signal(signal.SIGTERM, exit_handler)
20+
21+
22+
def collatz(n):
23+
steps = 0
24+
while n > 1:
25+
if n % 2:
26+
n = n * 3 + 1
27+
else:
28+
n = n // 2
29+
steps += 1
30+
return steps
31+
32+
33+
def collatz_consumer(target):
34+
count = 0
35+
while True:
36+
if not in_queue.empty():
37+
try:
38+
n = in_queue.get(timeout=1)
39+
except queue.Empty:
40+
return count
41+
42+
if collatz(n) == target:
43+
count += 1
44+
45+
if exit_event.is_set():
46+
return count
47+
48+
49+
def range_producer():
50+
for n in range(2, BOUND):
51+
if exit_event.is_set():
52+
return
53+
try:
54+
in_queue.put(n, timeout=1)
55+
except queue.Full:
56+
exit_event.set()
57+
return
58+
59+
while True:
60+
time.sleep(0.05)
61+
if in_queue.empty():
62+
exit_event.set()
63+
return
64+
65+
66+
def length_counter(target):
67+
with concurrent.futures.ProcessPoolExecutor() as executor:
68+
executor.submit(range_producer)
69+
results = executor.map(
70+
collatz_consumer,
71+
itertools.repeat(target, 4)
72+
)
73+
74+
return sum(results)
75+
76+
77+
def get_input(prompt):
78+
while True:
79+
n = input(prompt)
80+
try:
81+
n = int(n)
82+
except ValueError:
83+
print("Value must be an integer.")
84+
continue
85+
86+
if n <= 0:
87+
print("Value must be positive.")
88+
else:
89+
return n
90+
91+
92+
def main():
93+
print("Collatz Sequence Counter")
94+
95+
target = get_input("Collatz sequence length to search for: ")
96+
print(f"Searching in range 1-{BOUND}...")
97+
98+
with concurrent.futures.ThreadPoolExecutor() as executor:
99+
future_guess = executor.submit(
100+
get_input,
101+
"How many times do you think it will appear? "
102+
)
103+
104+
count = length_counter(target)
105+
106+
guess = future_guess.result()
107+
108+
if guess == count:
109+
print("Exactly right! I'm amazed.")
110+
elif abs(guess - count) < 100:
111+
print(f"You're close! It was {count}.")
112+
else:
113+
print(f"Nope. It was {count}.")
114+
115+
116+
if __name__ == "__main__":
117+
main()

Ch17/collatz_threaded.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import concurrent.futures
2+
3+
BOUND = 10**5
4+
5+
6+
def collatz(n):
7+
steps = 0
8+
while n > 1:
9+
if n % 2:
10+
n = n * 3 + 1
11+
else:
12+
n = n / 2
13+
steps += 1
14+
return steps
15+
16+
17+
def length_counter(target):
18+
count = 0
19+
for i in range(2, BOUND):
20+
if collatz(i) == target:
21+
count += 1
22+
return count
23+
24+
25+
guess = None
26+
27+
28+
def get_input(prompt):
29+
while True:
30+
n = input(prompt)
31+
try:
32+
n = int(n)
33+
except ValueError:
34+
print("Value must be an integer.")
35+
continue
36+
37+
if n <= 0:
38+
print("Value must be positive.")
39+
else:
40+
return n
41+
42+
43+
def main():
44+
print("Collatz Sequence Counter")
45+
46+
target = get_input("Collatz sequence length to search for: ")
47+
print(f"Searching in range 1-{BOUND}...")
48+
49+
with concurrent.futures.ThreadPoolExecutor() as executor:
50+
future_guess = executor.submit(
51+
get_input,
52+
"How many times do you think it will appear? "
53+
)
54+
55+
count = length_counter(target)
56+
57+
guess = future_guess.result()
58+
59+
if guess == count:
60+
print("Exactly right! I'm amazed.")
61+
elif abs(guess - count) < 100:
62+
print(f"You're close! It was {count}.")
63+
else:
64+
print(f"Nope. It was {count}.")
65+
66+
67+
if __name__ == "__main__":
68+
main()

Ch17/increment.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import dis
2+
3+
count = 0
4+
5+
def increment():
6+
global count
7+
count + 1
8+
9+
dis.dis(increment)

0 commit comments

Comments
 (0)