|
1 | 1 | #!/usr/bin/env python3 |
2 | 2 |
|
3 | 3 | """ |
4 | | -threads.py: shows that Python threads are slower than |
5 | | -sequential code for CPU-intensive work. |
| 4 | +threads.py: shows that Python threads are slower |
| 5 | +than sequential code for CPU-intensive work. |
6 | 6 | """ |
7 | 7 |
|
8 | 8 | import os |
|
14 | 14 |
|
15 | 15 | from primes import is_prime, NUMBERS |
16 | 16 |
|
17 | | -class PrimeResult(NamedTuple):# <3> |
| 17 | +class PrimeResult(NamedTuple): |
18 | 18 | n: int |
19 | 19 | prime: bool |
20 | 20 | elapsed: float |
21 | 21 |
|
22 | | -JobQueue = SimpleQueue[int] |
23 | | -ResultQueue = SimpleQueue[PrimeResult] |
| 22 | +JobQueue = SimpleQueue[int]# <4> |
| 23 | +ResultQueue = SimpleQueue[PrimeResult]# <5> |
24 | 24 |
|
25 | | -def check(n: int) -> PrimeResult: |
| 25 | +def check(n: int) -> PrimeResult:# <6> |
26 | 26 | t0 = perf_counter() |
27 | 27 | res = is_prime(n) |
28 | 28 | return PrimeResult(n, res, perf_counter() - t0) |
29 | 29 |
|
30 | | -def worker(jobs: JobQueue, results: ResultQueue) -> None: |
31 | | - while n := jobs.get(): |
32 | | - results.put(check(n)) |
33 | | - |
34 | | -def main() -> None: |
35 | | - if len(sys.argv) < 2: # <1> |
36 | | - workers = os.cpu_count() or 1 # make mypy happy |
37 | | - else: |
38 | | - workers = int(sys.argv[1]) |
39 | | - |
40 | | - print(f'Checking {len(NUMBERS)} numbers with {workers} threads:') |
41 | | - |
42 | | - jobs: JobQueue = SimpleQueue() # <2> |
43 | | - results: ResultQueue = SimpleQueue() |
44 | | - t0 = perf_counter() |
| 30 | +def worker(jobs: JobQueue, results: ResultQueue) -> None: # <7> |
| 31 | + while n := jobs.get(): # <8> |
| 32 | + results.put(check(n)) # <9> |
| 33 | + results.put(PrimeResult(0, False, 0.0)) |
45 | 34 |
|
| 35 | +def start_jobs(workers: int, jobs: JobQueue, results: ResultQueue) -> None: |
46 | 36 | for n in NUMBERS: # <3> |
47 | 37 | jobs.put(n) |
48 | | - |
49 | 38 | for _ in range(workers): |
50 | 39 | proc = Thread(target=worker, args=(jobs, results)) # <4> |
51 | 40 | proc.start() # <5> |
52 | 41 | jobs.put(0) # <6> |
53 | 42 |
|
54 | | - while True: |
55 | | - n, prime, elapsed = results.get() # <7> |
56 | | - label = 'P' if prime else ' ' |
57 | | - print(f'{n:16} {label} {elapsed:9.6f}s') |
58 | | - if jobs.empty(): # <8> |
59 | | - break |
| 43 | +def report(workers: int, results: ResultQueue) -> int: |
| 44 | + checked = 0 |
| 45 | + workers_done = 0 |
| 46 | + while workers_done < workers: |
| 47 | + n, prime, elapsed = results.get() |
| 48 | + if n == 0: |
| 49 | + workers_done += 1 |
| 50 | + else: |
| 51 | + checked += 1 |
| 52 | + label = 'P' if prime else ' ' |
| 53 | + print(f'{n:16} {label} {elapsed:9.6f}s') |
| 54 | + return checked |
| 55 | + |
| 56 | +def main() -> None: |
| 57 | + if len(sys.argv) < 2: |
| 58 | + workers = os.cpu_count() |
| 59 | + else: |
| 60 | + workers = int(sys.argv[1]) |
60 | 61 |
|
| 62 | + print(f'Checking {len(NUMBERS)} numbers with {workers} threads:') |
| 63 | + t0 = perf_counter() |
| 64 | + jobs: JobQueue = SimpleQueue() |
| 65 | + results: ResultQueue = SimpleQueue() |
| 66 | + start_jobs(workers, jobs, results) |
| 67 | + checked = report(workers, results) |
61 | 68 | elapsed = perf_counter() - t0 |
62 | | - print(f'Total time: {elapsed:.2f}s') |
| 69 | + print(f'{checked} checks in {elapsed:.2f}s') |
63 | 70 |
|
64 | 71 | if __name__ == '__main__': |
65 | 72 | main() |
| 73 | + |
0 commit comments