Skip to content

Commit bef2287

Browse files
committed
feat: fill out more Python examples for multithreading
Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
1 parent 2d2a6a7 commit bef2287

File tree

7 files changed

+529
-36
lines changed

7 files changed

+529
-36
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import contextlib
2+
import time
3+
4+
import numpy as np
5+
6+
7+
@contextlib.contextmanager
8+
def timer():
9+
start = time.monotonic()
10+
yield
11+
print(f"Took {time.monotonic() - start}s to run")
12+
13+
14+
def prepare(height, width):
15+
c = np.sum(
16+
np.broadcast_arrays(*np.ogrid[-1j : 0j : height * 1j, -1.5 : 0 : width * 1j]),
17+
axis=0,
18+
)
19+
fractal = np.zeros_like(c, dtype=np.int32)
20+
return c, fractal
21+
22+
23+
@timer()
24+
def run(c, fractal, maxiterations=20):
25+
z = c
26+
27+
for i in range(1, maxiterations + 1):
28+
z = z**2 + c # Compute z
29+
diverge = abs(z) > 2 # Divergence criteria
30+
31+
z[diverge] = 2 # Keep number size small
32+
fractal[~diverge] = i # Fill in non-diverged iteration number
33+
34+
35+
size = 4000, 3000
36+
37+
c, fractal = prepare(*size)
38+
fractal = run(c, fractal)
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import contextlib
2+
import random
3+
import statistics
4+
import threading
5+
import time
6+
import asyncio
7+
8+
9+
@contextlib.asynccontextmanager
10+
async def timer():
11+
start = time.monotonic()
12+
yield
13+
print(f"Took {time.monotonic() - start:.3}s to run")
14+
15+
16+
def pi_each(trials: int) -> None:
17+
Ncirc = 0
18+
rand = random.Random()
19+
20+
for _ in range(trials):
21+
x = rand.uniform(-1, 1)
22+
y = rand.uniform(-1, 1)
23+
24+
if x * x + y * y <= 1:
25+
Ncirc += 1
26+
27+
return 4.0 * (Ncirc / trials)
28+
29+
30+
async def pi_async(trials: int):
31+
return await asyncio.to_thread(pi_each, trials)
32+
33+
34+
@timer()
35+
async def pi_all(trials: int, threads: int) -> float:
36+
async with asyncio.TaskGroup() as tg:
37+
tasks = [tg.create_task(pi_async(trials // threads)) for _ in range(threads)]
38+
return statistics.mean(t.result() for t in tasks)
39+
40+
41+
def pi(trials: int, threads: int) -> float:
42+
return asyncio.run(pi_all(trials, threads))
43+
44+
45+
print(f"{pi(10_000_000, 10)=}")
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import contextlib
2+
import random
3+
import statistics
4+
import time
5+
from concurrent.futures import ProcessPoolExecutor
6+
7+
8+
@contextlib.contextmanager
9+
def timer():
10+
start = time.monotonic()
11+
yield
12+
print(f"Took {time.monotonic() - start:.3}s to run")
13+
14+
15+
def pi_each(trials: int) -> None:
16+
Ncirc = 0
17+
18+
for _ in range(trials):
19+
x = random.uniform(-1, 1)
20+
y = random.uniform(-1, 1)
21+
22+
if x * x + y * y <= 1:
23+
Ncirc += 1
24+
25+
return 4.0 * (Ncirc / trials)
26+
27+
28+
@timer()
29+
def pi(trials: int, threads: int) -> float:
30+
with ProcessPoolExecutor() as pool:
31+
futures = pool.map(pi_each, [trials // threads] * threads)
32+
return statistics.mean(futures)
33+
34+
35+
if __name__ == "__main__":
36+
print(f"{pi(10_000_000, 10)=}")

content/week11/piexample/single.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import contextlib
2+
import random
3+
import statistics
4+
import time
5+
6+
7+
@contextlib.contextmanager
8+
def timer():
9+
start = time.monotonic()
10+
yield
11+
print(f"Took {time.monotonic() - start:.3}s to run")
12+
13+
14+
@timer()
15+
def pi(trials: int) -> float:
16+
Ncirc = 0
17+
18+
for _ in range(trials):
19+
x = random.uniform(-1, 1)
20+
y = random.uniform(-1, 1)
21+
22+
if x * x + y * y <= 1:
23+
Ncirc += 1
24+
25+
return 4.0 * (Ncirc / trials)
26+
27+
28+
print(f"{pi(10_000_000)=}")

content/week11/piexample/thread.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import contextlib
2+
import random
3+
import statistics
4+
import threading
5+
import time
6+
import queue
7+
8+
9+
@contextlib.contextmanager
10+
def timer():
11+
start = time.monotonic()
12+
yield
13+
print(f"Took {time.monotonic() - start:.3}s to run")
14+
15+
16+
def pi_each(q: queue.Queue, trials: int) -> None:
17+
Ncirc = 0
18+
rand = random.Random()
19+
20+
for _ in range(trials):
21+
x = rand.uniform(-1, 1)
22+
y = rand.uniform(-1, 1)
23+
24+
if x * x + y * y <= 1:
25+
Ncirc += 1
26+
27+
q.put(4.0 * (Ncirc / trials))
28+
29+
30+
@timer()
31+
def pi(trials: int, threads: int) -> float:
32+
q = queue.Queue()
33+
workers = [
34+
threading.Thread(target=pi_each, args=(q, trials // threads))
35+
for _ in range(threads)
36+
]
37+
for worker in workers:
38+
worker.start()
39+
for worker in workers:
40+
worker.join()
41+
return statistics.mean(q.get() for _ in range(q.qsize()))
42+
43+
44+
print(f"{pi(10_000_000, 10)=}")
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import contextlib
2+
import random
3+
import statistics
4+
import time
5+
from concurrent.futures import ThreadPoolExecutor
6+
7+
8+
@contextlib.contextmanager
9+
def timer():
10+
start = time.monotonic()
11+
yield
12+
print(f"Took {time.monotonic() - start:.3}s to run")
13+
14+
15+
def pi_each(trials: int) -> None:
16+
Ncirc = 0
17+
rand = random.Random()
18+
19+
for _ in range(trials):
20+
x = rand.uniform(-1, 1)
21+
y = rand.uniform(-1, 1)
22+
23+
if x * x + y * y <= 1:
24+
Ncirc += 1
25+
26+
return 4.0 * (Ncirc / trials)
27+
28+
29+
@timer()
30+
def pi(trials: int, threads: int) -> float:
31+
with ThreadPoolExecutor() as pool:
32+
futures = pool.map(pi_each, [trials // threads] * threads)
33+
return statistics.mean(futures)
34+
35+
36+
print(f"{pi(10_000_000, 10)=}")

0 commit comments

Comments
 (0)