ch20 files

This commit is contained in:
Luciano Ramalho
2021-01-29 21:05:03 -03:00
parent 07856d4f30
commit a3bf91bc59
9 changed files with 945 additions and 28 deletions

View File

@@ -0,0 +1,260 @@
1 42.05
2 22.81
3 15.95
4 13.28
5 12.27
6 10.38
7 11.00
8 11.41
9 12.17
10 12.69
11 11.34
12 11.35
13 10.88
14 11.63
15 11.79
16 11.49
17 11.29
18 10.78
19 10.92
20 11.07
1 40.47
2 22.93
3 15.88
4 13.25
5 12.22
6 10.95
7 10.81
8 11.26
9 11.96
10 12.43
11 11.19
12 10.91
13 11.03
14 10.56
15 10.62
16 11.73
17 11.00
18 12.81
19 12.38
20 11.28
1 40.81
2 22.79
3 15.83
4 13.27
5 12.33
6 10.65
7 10.94
8 11.48
9 11.78
10 12.78
11 11.31
12 10.97
13 10.80
14 10.93
15 10.69
16 10.57
17 10.54
18 10.55
19 10.79
20 10.64
1 40.85
2 22.67
3 16.05
4 13.21
5 12.53
6 10.84
7 10.80
8 11.31
9 11.69
10 12.51
11 11.22
12 11.35
13 11.00
14 10.64
15 10.89
16 10.49
17 10.55
18 10.76
19 10.54
20 10.75
1 40.41
2 22.75
3 15.87
4 13.19
5 12.33
6 10.50
7 10.84
8 11.55
9 11.79
10 12.53
11 11.24
12 11.13
13 10.89
14 10.52
15 10.74
16 10.68
17 10.88
18 10.61
19 11.07
20 10.71
1 40.45
2 22.73
3 16.35
4 13.09
5 12.19
6 10.39
7 11.01
8 11.30
9 11.81
10 12.24
11 11.21
12 11.13
13 10.66
14 10.56
15 10.91
16 10.49
17 10.58
18 10.61
19 10.60
20 10.69
1 40.36
2 22.64
3 15.95
4 13.20
5 12.27
6 10.34
7 10.47
8 11.34
9 11.68
10 12.30
11 11.04
12 10.85
13 10.78
14 10.64
15 10.63
16 10.58
17 10.67
18 10.64
19 10.71
20 10.68
1 40.70
2 22.71
3 15.81
4 13.10
5 12.29
6 10.34
7 10.40
8 11.40
9 11.71
10 12.56
11 11.29
12 10.99
13 10.51
14 10.69
15 10.53
16 11.04
17 10.67
18 10.71
19 10.86
20 10.78
1 40.69
2 22.80
3 15.88
4 13.13
5 12.19
6 10.36
7 10.77
8 11.32
9 11.66
10 12.29
11 11.06
12 10.89
13 10.66
14 10.61
15 10.36
16 10.57
17 10.94
18 10.57
19 10.81
20 10.72
1 40.81
2 22.76
3 15.84
4 13.10
5 12.25
6 10.33
7 10.58
8 11.51
9 11.69
10 12.45
11 11.51
12 11.53
13 10.61
14 10.52
15 10.57
16 10.57
17 10.76
18 10.60
19 10.66
20 10.73
1 40.84
2 22.83
3 15.86
4 13.27
5 12.39
6 10.45
7 10.87
8 11.42
9 11.70
10 12.55
11 11.43
12 10.98
13 10.81
14 10.69
15 10.68
16 10.71
17 10.80
18 10.76
19 10.90
20 11.02
1 40.99
2 22.99
3 16.10
4 13.46
5 12.45
6 10.47
7 10.79
8 11.74
9 11.64
10 12.37
11 11.20
12 11.09
13 10.82
14 10.61
15 10.56
16 10.53
17 10.60
18 10.81
19 10.72
20 10.62
1 40.94
2 23.09
3 16.03
4 13.40
5 12.51
6 10.38
7 10.58
8 11.37
9 11.75
10 12.87
11 12.11
12 11.37
13 11.84
14 11.30
15 11.29
16 11.36
17 11.01
18 11.37
19 11.07
20 10.94

View File

@@ -1,8 +1,9 @@
# tag::PRIMES_PROC_TOP[] # tag::PRIMES_PROC_TOP[]
from time import perf_counter from time import perf_counter
from typing import Tuple, List, NamedTuple from typing import Tuple, NamedTuple
from multiprocessing import Process, SimpleQueue # <1> from multiprocessing import Process, SimpleQueue, cpu_count # <1>
from multiprocessing import queues # <2> from multiprocessing import queues # <2>
import sys
from primes import is_prime, NUMBERS from primes import is_prime, NUMBERS
@@ -10,33 +11,47 @@ class Result(NamedTuple): # <3>
flag: bool flag: bool
elapsed: float elapsed: float
JobQueue = queues.SimpleQueue[Tuple[int, Result]] # <4> JobQueue = queues.SimpleQueue[int] # <4>
ResultQueue = queues.SimpleQueue[Tuple[int, Result]] # <5>
def check(n: int) -> Result: # <5> def check(n: int) -> Result: # <6>
t0 = perf_counter() t0 = perf_counter()
res = is_prime(n) res = is_prime(n)
return Result(res, perf_counter() - t0) return Result(res, perf_counter() - t0)
def job(n: int, results: JobQueue) -> None: # <6> def worker(jobs: JobQueue, results: ResultQueue) -> None: # <7>
results.put((n, check(n))) # <7> while n := jobs.get(): # <8>
result = check(n) # <9>
results.put((n, result)) # <10>
# end::PRIMES_PROC_TOP[] # end::PRIMES_PROC_TOP[]
# tag::PRIMES_PROC_MAIN[] # tag::PRIMES_PROC_MAIN[]
def main() -> None: def main() -> None:
if len(sys.argv) < 2: # <1>
workers = cpu_count()
else:
workers = int(sys.argv[1])
t0 = perf_counter() t0 = perf_counter()
results: JobQueue = SimpleQueue() # <1> jobs: JobQueue = SimpleQueue() # <2>
workers: List[Process] = [] # <2> results: ResultQueue = SimpleQueue()
for n in NUMBERS: print(f'Checking {len(NUMBERS)} numbers with {workers} processes:')
worker = Process(target=job, args=(n, results)) # <3>
worker.start() # <4>
workers.append(worker) # <5>
for _ in workers: # <6> for n in NUMBERS: # <3>
jobs.put(n)
for _ in range(workers):
proc = Process(target=worker, args=(jobs, results)) # <4>
proc.start() # <5>
jobs.put(0) # <6>
while True:
n, (prime, elapsed) = results.get() # <7> n, (prime, elapsed) = results.get() # <7>
label = 'P' if prime else ' ' label = 'P' if prime else ' '
print(f'{n:16} {label} {elapsed:9.6f}s') print(f'{n:16} {label} {elapsed:9.6f}s') # <8>
if jobs.empty(): # <9>
break
time = perf_counter() - t0 time = perf_counter() - t0
print('Total time:', f'{time:0.2f}s') print('Total time:', f'{time:0.2f}s')

View File

@@ -0,0 +1,2 @@
#/bin/bash
for i in {1..20}; do echo -n $i; python3 procs.py $i | tail -1; done

View File

@@ -0,0 +1,40 @@
# spinner_async_experiment.py
# credits: Example by Luciano Ramalho inspired by
# Michele Simionato's multiprocessing example in the python-list:
# https://mail.python.org/pipermail/python-list/2009-February/675659.html
import asyncio
import itertools
import primes
async def spin(msg: str) -> None:
for char in itertools.cycle(r'\|/-'):
status = f'\r{char} {msg}'
print(status, flush=True, end='')
try:
await asyncio.sleep(.1)
except asyncio.CancelledError:
break
print('THIS WILL NEVER BE OUTPUT')
async def check(n: int) -> int:
return primes.is_prime(n) # <4>
async def supervisor(n: int) -> int:
spinner = asyncio.create_task(spin('thinking!')) # <1>
print('spinner object:', spinner) # <2>
result = await check(n) # <3>
spinner.cancel() # <5>
return result
# end::SPINNER_ASYNC_EXPERIMENT[]
def main() -> None:
n = 5_000_111_000_222_021
result = asyncio.run(supervisor(n))
msg = 'is' if result else 'is not'
print(f'{n:,} {msg} prime')
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,59 @@
# spinner_async_experiment.py
# credits: Example by Luciano Ramalho inspired by
# Michele Simionato's multiprocessing example in the python-list:
# https://mail.python.org/pipermail/python-list/2009-February/675659.html
import asyncio
import itertools
import math
# tag::SPINNER_ASYNC_NAP[]
async def is_prime(n):
if n < 2:
return False
if n == 2:
return True
if n % 2 == 0:
return False
sleep = asyncio.sleep # <1>
root = int(math.floor(math.sqrt(n)))
for i in range(3, root + 1, 2):
if n % i == 0:
return False
if i % 100_000 == 1: # <2>
await sleep(0)
return True
# end::SPINNER_ASYNC_NAP[]
async def spin(msg: str) -> None:
for char in itertools.cycle(r'\|/-'):
status = f'\r{char} {msg}'
print(status, flush=True, end='')
try:
await asyncio.sleep(.1)
except asyncio.CancelledError:
break
blanks = ' ' * len(status)
print(f'\r{blanks}\r', end='')
async def check(n: int) -> int:
return await is_prime(n) # <4>
async def supervisor(n: int) -> int:
spinner = asyncio.create_task(spin('thinking!')) # <1>
print('spinner object:', spinner) # <2>
result = await check(n) # <3>
spinner.cancel() # <5>
return result
def main() -> None:
n = 5_000_111_000_222_021
result = asyncio.run(supervisor(n))
msg = 'is' if result else 'is not'
print(f'{n:,} {msg} prime')
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,44 @@
# spinner_prime_proc.py
# credits: Adapted from Michele Simionato's
# multiprocessing example in the python-list:
# https://mail.python.org/pipermail/python-list/2009-February/675659.html
from multiprocessing import Process, Event
from multiprocessing import synchronize
import itertools
import time
from primes import is_prime
def spin(msg: str, done: synchronize.Event) -> None: # <1>
for char in itertools.cycle(r'\|/-'): # <2>
status = f'\r{char} {msg}' # <3>
print(status, end='', flush=True)
if done.wait(.1): # <4>
break # <5>
blanks = ' ' * len(status)
print(f'\r{blanks}\r', end='') # <6>
def check(n: int) -> int:
return is_prime(n)
def supervisor(n: int) -> int: # <1>
done = Event() # <2>
spinner = Process(target=spin,
args=('thinking!', done)) # <3>
print('spinner object:', spinner) # <4>
spinner.start() # <5>
result = check(n) # <6>
done.set() # <7>
spinner.join() # <8>
return result
def main() -> None:
n = 5_000_111_000_222_021
result = supervisor(n) # <9>
msg = 'is' if result else 'is not'
print(f'{n:,} {msg} prime')
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,43 @@
# spinner_prime_thread.py
# credits: Adapted from Michele Simionato's
# multiprocessing example in the python-list:
# https://mail.python.org/pipermail/python-list/2009-February/675659.html
from threading import Thread, Event
import itertools
import time
from primes import is_prime
def spin(msg: str, done: Event) -> None: # <1>
for char in itertools.cycle(r'\|/-'): # <2>
status = f'\r{char} {msg}' # <3>
print(status, end='', flush=True)
if done.wait(.1): # <4>
break # <5>
blanks = ' ' * len(status)
print(f'\r{blanks}\r', end='') # <6>
def check(n: int) -> int:
return is_prime(n)
def supervisor(n: int) -> int: # <1>
done = Event() # <2>
spinner = Thread(target=spin,
args=('thinking!', done)) # <3>
print('spinner object:', spinner) # <4>
spinner.start() # <5>
result = check(n) # <6>
done.set() # <7>
spinner.join() # <8>
return result
def main() -> None:
n = 5_000_111_000_222_021
result = supervisor(n) # <9>
msg = 'is' if result else 'is not'
print(f'{n:,} {msg} prime')
if __name__ == '__main__':
main()

File diff suppressed because one or more lines are too long

View File

@@ -1,38 +1,55 @@
from time import perf_counter from time import perf_counter
from typing import Tuple, List, NamedTuple from typing import Tuple, NamedTuple
from threading import Thread from threading import Thread
from queue import SimpleQueue from queue import SimpleQueue
import sys
import os
from primes import is_prime, NUMBERS from primes import is_prime, NUMBERS
class Result(NamedTuple): # <3> class Result(NamedTuple):
flag: bool flag: bool
elapsed: float elapsed: float
JobQueue = SimpleQueue[Tuple[int, Result]] # <4> JobQueue = SimpleQueue[int]
ResultQueue = SimpleQueue[Tuple[int, Result]]
def check(n: int) -> Result: # <5> def check(n: int) -> Result:
t0 = perf_counter() t0 = perf_counter()
res = is_prime(n) res = is_prime(n)
return Result(res, perf_counter() - t0) return Result(res, perf_counter() - t0)
def job(n: int, results: JobQueue) -> None: # <6> def worker(jobs: JobQueue, results: ResultQueue) -> None:
results.put((n, check(n))) # <7> while n := jobs.get():
result = check(n)
results.put((n, result))
def main() -> None: def main() -> None:
if len(sys.argv) < 2: # <1>
workers = os.cpu_count() or 1 # make mypy happy
else:
workers = int(sys.argv[1])
t0 = perf_counter() t0 = perf_counter()
results: JobQueue = SimpleQueue() # <1> jobs: JobQueue = SimpleQueue() # <2>
workers: List[Thread] = [] # <2> results: ResultQueue = SimpleQueue()
for n in NUMBERS: print(f'Checking {len(NUMBERS)} numbers with {workers} threads:')
worker = Thread(target=job, args=(n, results)) # <3>
worker.start() # <4>
workers.append(worker) # <5>
for _ in workers: # <6> for n in NUMBERS: # <3>
jobs.put(n)
for _ in range(workers):
proc = Thread(target=worker, args=(jobs, results)) # <4>
proc.start() # <5>
jobs.put(0) # <6>
while True:
n, (prime, elapsed) = results.get() # <7> n, (prime, elapsed) = results.get() # <7>
label = 'P' if prime else ' ' label = 'P' if prime else ' '
print(f'{n:16} {label} {elapsed:9.6f}s') print(f'{n:16} {label} {elapsed:9.6f}s')
if jobs.empty(): # <8>
break
time = perf_counter() - t0 time = perf_counter() - t0
print('Total time:', f'{time:0.2f}s') print('Total time:', f'{time:0.2f}s')