remove outdated exercise
|
@ -1,27 +0,0 @@
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
|
|
||||||
# This module provides the magic_signature() function, safely and
|
|
||||||
# securely calculated to provide invaluable signature of an image.
|
|
||||||
|
|
||||||
def magic(fname):
|
|
||||||
n_threads = os.getenv('OMP_NUM_THREADS', '(unset)')
|
|
||||||
print(f"Worker {fname=} OMP_NUM_THREADS={n_threads}")
|
|
||||||
|
|
||||||
# We delay the import of numpy because we want to set OMP_NUM_THREADS.
|
|
||||||
# We delay the import of PIL in case is uses numpy internally.
|
|
||||||
|
|
||||||
import numpy as np
|
|
||||||
from PIL import Image
|
|
||||||
|
|
||||||
im = Image.open(fname)
|
|
||||||
try:
|
|
||||||
m = np.median(im, axis=2)
|
|
||||||
except np.AxisError:
|
|
||||||
return -1
|
|
||||||
n = (m @ m.T).mean()
|
|
||||||
return int(n)
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
for fname in sys.argv[1:]:
|
|
||||||
print(f'{fname} → {magic(fname)}')
|
|
|
@ -1,35 +0,0 @@
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import time
|
|
||||||
|
|
||||||
from process_multiple_images import process
|
|
||||||
|
|
||||||
n_threads = ...
|
|
||||||
n_processes = ...
|
|
||||||
|
|
||||||
def measure_one(n_processes, n_threads, fnames):
|
|
||||||
result_fname = f'{n_processes:02}_{n_threads:02}.txt'
|
|
||||||
|
|
||||||
if os.path.exists(result_fname):
|
|
||||||
print(f'Skipping job with {n_processes} processes and {n_threads} threads, results file exists')
|
|
||||||
return
|
|
||||||
|
|
||||||
t0 = time.time()
|
|
||||||
process(n_processes, n_threads, fnames)
|
|
||||||
dt = time.time() - t0
|
|
||||||
|
|
||||||
print(f'Job with {n_processes} processes and {n_threads} threads/worker and {len(fnames)} jobs: {dt}')
|
|
||||||
|
|
||||||
with open(result_fname, 'wt') as results:
|
|
||||||
print(f'{n_processes:02} {n_threads:02} {dt}', file=results)
|
|
||||||
|
|
||||||
def measure(n_processes, n_threads, fnames):
|
|
||||||
for n1 in n_processes:
|
|
||||||
for n2 in n_threads:
|
|
||||||
measure_one(n1, n2, fnames)
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
measure(
|
|
||||||
[1, 2, 3, 4, 5, 6, 7, 8, 9],
|
|
||||||
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
|
|
||||||
sys.argv[1:])
|
|
|
@ -1,25 +0,0 @@
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
from multiprocessing import Pool as ProcessPool
|
|
||||||
|
|
||||||
import process_image
|
|
||||||
|
|
||||||
def process(n_processes, n_threads, fnames):
|
|
||||||
print(f"Controller with {n_processes} processes and {n_threads} threads / worker")
|
|
||||||
|
|
||||||
# The environment that is set in the parent is inherited by child workers,
|
|
||||||
# but here process_image import numpy, so we need to set the variable
|
|
||||||
# before process_image is imported.
|
|
||||||
os.environ['OMP_NUM_THREADS'] = str(n_threads)
|
|
||||||
|
|
||||||
with ProcessPool(n_processes) as p:
|
|
||||||
signatures = p.map(process_image.magic, fnames)
|
|
||||||
for fname, signature in zip(fnames, signatures):
|
|
||||||
print(f'{fname} → {signature}')
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
n_processes = int(sys.argv[1])
|
|
||||||
n_threads = int(sys.argv[2])
|
|
||||||
fnames = sys.argv[3:]
|
|
||||||
|
|
||||||
process(n_processes, n_threads, fnames)
|
|
|
@ -1,20 +0,0 @@
|
||||||
## Exercise 2c
|
|
||||||
|
|
||||||
Processing images with simultaneous multiprocessing and multithreading.
|
|
||||||
|
|
||||||
`process_image.py` processes a single image.
|
|
||||||
It can be used as a script: `process_image.py foo.jpg`
|
|
||||||
It is also an importable module. `process_image.magic("foo.jpg")`
|
|
||||||
|
|
||||||
`process_multiple_images` uses `process_image` to process a series of images.
|
|
||||||
It should be called as following:
|
|
||||||
`process_multiple_images n_processes n_threads filename1.png filename2.png …`
|
|
||||||
|
|
||||||
1. start a separate terminal window with `htop`: `gnome-terminal -- htop &`
|
|
||||||
|
|
||||||
2. call `python process_multiple_images.py 2 2 images/*.png`
|
|
||||||
|
|
||||||
You should see `htop` showing 4 threads (2 worked processes × 2 numpy threads).
|
|
||||||
|
|
||||||
Play with different numbers of processes and threads.
|
|
||||||
Which combination is optimum (fastest)?
|
|
Before Width: | Height: | Size: 422 KiB |
Before Width: | Height: | Size: 289 KiB |
Before Width: | Height: | Size: 280 KiB |
Before Width: | Height: | Size: 246 KiB |
Before Width: | Height: | Size: 262 KiB |
Before Width: | Height: | Size: 280 KiB |
Before Width: | Height: | Size: 493 KiB |
Before Width: | Height: | Size: 453 KiB |
Before Width: | Height: | Size: 493 KiB |
Before Width: | Height: | Size: 515 KiB |
Before Width: | Height: | Size: 468 KiB |
Before Width: | Height: | Size: 515 KiB |
Before Width: | Height: | Size: 348 KiB |
Before Width: | Height: | Size: 357 KiB |
Before Width: | Height: | Size: 348 KiB |
Before Width: | Height: | Size: 222 KiB |
Before Width: | Height: | Size: 221 KiB |
Before Width: | Height: | Size: 666 KiB |
Before Width: | Height: | Size: 607 KiB |