Skip to content

Commit 916ceaa

Browse files
committed
ch20: minor edits
1 parent 33f73a1 commit 916ceaa

File tree

5 files changed

+58
-35
lines changed

5 files changed

+58
-35
lines changed

20-concurrency/primes/primes.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#!/usr/bin/env python3
2+
13
import math
24

35

@@ -27,15 +29,15 @@
2729
NUMBERS = [n for n, _ in PRIME_FIXTURE]
2830

2931
# tag::IS_PRIME[]
30-
def is_prime(n) -> bool:
32+
def is_prime(n: int) -> bool:
3133
if n < 2:
3234
return False
3335
if n == 2:
3436
return True
3537
if n % 2 == 0:
3638
return False
3739

38-
root = math.floor(math.sqrt(n))
40+
root = math.isqrt(n)
3941
for i in range(3, root + 1, 2):
4042
if n % i == 0:
4143
return False

20-concurrency/primes/procs.py

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,35 @@
1+
#!/usr/bin/env python3
2+
3+
"""
4+
procs.py: shows that multiprocessing on a multicore machine
5+
can be faster than sequential code for CPU-intensive work.
6+
"""
7+
18
# tag::PRIMES_PROC_TOP[]
29
from time import perf_counter
3-
from typing import Tuple, NamedTuple
10+
from typing import NamedTuple
411
from multiprocessing import Process, SimpleQueue, cpu_count # <1>
512
from multiprocessing import queues # <2>
613
import sys
714

815
from primes import is_prime, NUMBERS
916

10-
class Result(NamedTuple): # <3>
11-
flag: bool
17+
class PrimeResult(NamedTuple): # <3>
18+
n: int
19+
prime: bool
1220
elapsed: float
1321

1422
JobQueue = queues.SimpleQueue[int] # <4>
15-
ResultQueue = queues.SimpleQueue[Tuple[int, Result]] # <5>
23+
ResultQueue = queues.SimpleQueue[PrimeResult] # <5>
1624

17-
def check(n: int) -> Result: # <6>
25+
def check(n: int) -> PrimeResult: # <6>
1826
t0 = perf_counter()
1927
res = is_prime(n)
20-
return Result(res, perf_counter() - t0)
28+
return PrimeResult(n, res, perf_counter() - t0)
2129

2230
def worker(jobs: JobQueue, results: ResultQueue) -> None: # <7>
2331
while n := jobs.get(): # <8>
24-
result = check(n) # <9>
25-
results.put((n, result)) # <10>
32+
results.put(check(n)) # <9>
2633
# end::PRIMES_PROC_TOP[]
2734

2835
# tag::PRIMES_PROC_MAIN[]
@@ -32,11 +39,11 @@ def main() -> None:
3239
else:
3340
workers = int(sys.argv[1])
3441

35-
t0 = perf_counter()
42+
print(f'Checking {len(NUMBERS)} numbers with {workers} processes:')
43+
3644
jobs: JobQueue = SimpleQueue() # <2>
3745
results: ResultQueue = SimpleQueue()
38-
39-
print(f'Checking {len(NUMBERS)} numbers with {workers} processes:')
46+
t0 = perf_counter()
4047

4148
for n in NUMBERS: # <3>
4249
jobs.put(n)
@@ -47,7 +54,7 @@ def main() -> None:
4754
jobs.put(0) # <6>
4855

4956
while True:
50-
n, (prime, elapsed) = results.get() # <7>
57+
n, prime, elapsed = results.get() # <7>
5158
label = 'P' if prime else ' '
5259
print(f'{n:16} {label} {elapsed:9.6f}s') # <8>
5360
if jobs.empty(): # <9>

20-concurrency/primes/sequential.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,26 @@
1+
#!/usr/bin/env python3
2+
3+
"""
4+
sequential.py: baseline for comparing sequential, multiprocessing,
5+
and threading code for CPU-intensive work.
6+
"""
7+
18
from time import perf_counter
29
from typing import NamedTuple
310

411
from primes import is_prime, NUMBERS
512

613
class Result(NamedTuple): # <1>
7-
flag: bool
14+
prime: bool
815
elapsed: float
916

1017
def check(n: int) -> Result: # <2>
1118
t0 = perf_counter()
12-
flag = is_prime(n)
13-
return Result(flag, perf_counter() - t0)
19+
prime = is_prime(n)
20+
return Result(prime, perf_counter() - t0)
1421

1522
def main() -> None:
23+
print(f'Checking {len(NUMBERS)} numbers sequentially:')
1624
t0 = perf_counter()
1725
for n in NUMBERS: # <3>
1826
prime, elapsed = check(n)

20-concurrency/primes/spinner_prime_async_nap.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# spinner_async_experiment.py
1+
# spinner_prime_async_nap.py
22

33
# credits: Example by Luciano Ramalho inspired by
44
# Michele Simionato's multiprocessing example in the python-list:
@@ -8,7 +8,7 @@
88
import itertools
99
import math
1010

11-
# tag::SPINNER_ASYNC_NAP[]
11+
# tag::PRIME_NAP[]
1212
async def is_prime(n):
1313
if n < 2:
1414
return False
@@ -17,15 +17,14 @@ async def is_prime(n):
1717
if n % 2 == 0:
1818
return False
1919

20-
sleep = asyncio.sleep # <1>
21-
root = math.floor(math.sqrt(n))
20+
root = math.isqrt(n)
2221
for i in range(3, root + 1, 2):
2322
if n % i == 0:
2423
return False
2524
if i % 100_000 == 1: # <2>
26-
await sleep(0)
25+
await asyncio.sleep(0)
2726
return True
28-
# end::SPINNER_ASYNC_NAP[]
27+
# end::PRIME_NAP[]
2928

3029

3130
async def spin(msg: str) -> None:

20-concurrency/primes/threads.py

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,47 @@
1+
#!/usr/bin/env python3
2+
3+
"""
4+
threads.py: shows that Python threads are slower than
5+
sequential code for CPU-intensive work.
6+
"""
7+
18
from time import perf_counter
2-
from typing import Tuple, NamedTuple
9+
from typing import NamedTuple
310
from threading import Thread
411
from queue import SimpleQueue
512
import sys
613
import os
714

815
from primes import is_prime, NUMBERS
916

10-
class Result(NamedTuple):
11-
flag: bool
17+
class PrimeResult(NamedTuple): # <3>
18+
n: int
19+
prime: bool
1220
elapsed: float
1321

1422
JobQueue = SimpleQueue[int]
15-
ResultQueue = SimpleQueue[Tuple[int, Result]]
23+
ResultQueue = SimpleQueue[PrimeResult]
1624

17-
def check(n: int) -> Result:
25+
def check(n: int) -> PrimeResult:
1826
t0 = perf_counter()
1927
res = is_prime(n)
20-
return Result(res, perf_counter() - t0)
28+
return PrimeResult(n, res, perf_counter() - t0)
2129

2230
def worker(jobs: JobQueue, results: ResultQueue) -> None:
2331
while n := jobs.get():
24-
result = check(n)
25-
results.put((n, result))
32+
results.put(check(n))
2633

2734
def main() -> None:
2835
if len(sys.argv) < 2: # <1>
2936
workers = os.cpu_count() or 1 # make mypy happy
3037
else:
3138
workers = int(sys.argv[1])
3239

33-
t0 = perf_counter()
40+
print(f'Checking {len(NUMBERS)} numbers with {workers} threads:')
41+
3442
jobs: JobQueue = SimpleQueue() # <2>
3543
results: ResultQueue = SimpleQueue()
36-
37-
print(f'Checking {len(NUMBERS)} numbers with {workers} threads:')
44+
t0 = perf_counter()
3845

3946
for n in NUMBERS: # <3>
4047
jobs.put(n)
@@ -45,7 +52,7 @@ def main() -> None:
4552
jobs.put(0) # <6>
4653

4754
while True:
48-
n, (prime, elapsed) = results.get() # <7>
55+
n, prime, elapsed = results.get() # <7>
4956
label = 'P' if prime else ' '
5057
print(f'{n:16} {label} {elapsed:9.6f}s')
5158
if jobs.empty(): # <8>

0 commit comments

Comments
 (0)