abey79 / vpype

The Swiss-Army-knife command-line tool for plotter vector graphics.
https://vpype.readthedocs.io/
MIT License
687 stars 61 forks source link

LineCollection: Parallelise Numpy operations #197

Open abey79 opened 3 years ago

abey79 commented 3 years ago

Most numpy operations release the GIL and are thus well suited for threaded parallelisation.

abey79 commented 3 years ago
import random
import timeit
import matplotlib.pyplot as plt
from multiprocessing.dummy import Pool

import numpy as np
import vpype as vp

thread_pool = Pool()

random.seed(0)
N1 = 10000
dataset1 = [vp.circle(0, 0, random.uniform(100, 1000), 0.1) for _ in range(N1)]

def translate_basic(lc, c):
    return [line + c for line in lc]

def translate_threaded(lc, c):
    def _translate(line):
        return line + c

    return list(thread_pool.map(_translate, lc, chunksize=50))

offset =  complex(150, 450)

iter_count = np.round(np.linspace(1, N1, 25)).astype(int)
times_basic = []
times_threaded = []
for n in iter_count:
    times_basic.append(timeit.timeit(lambda:translate_basic(dataset1[:n], offset), number=20))
    times_threaded.append(timeit.timeit(lambda: translate_threaded(dataset1[:n], offset), number=20))

thread_pool.close()
thread_pool.terminate()

plt.plot(iter_count, times_basic, '.-r')
plt.plot(iter_count, times_threaded, '.-b')
plt.show()
image
abey79 commented 3 years ago
N2 = 50000
dataset2 = [vp.line(
    random.uniform(0, 1000),
    random.uniform(0, 1000),
    random.uniform(0, 1000),
    random.uniform(0, 1000),
) for _ in range(N2)]
image
abey79 commented 3 years ago
import random
import timeit
import matplotlib.pyplot as plt
from multiprocessing.dummy import Pool

import numpy as np

thread_pool = Pool()

line_lengths = np.concatenate(
    [np.arange(2, 2500, 50), np.arange(2500, 5000, 100), np.arange(5000, 10000, 200),
     np.arange(10000, 20000, 500)])

random.seed(0)
N = 10000

def translate_basic(lc, c):
    return [line + c for line in lc]

def translate_threaded(lc, c):
    def _translate(line):
        return line + c

    return list(thread_pool.map(_translate, lc, chunksize=50))

offset = complex(150, 450)

times_basic = []
times_threaded = []

for line_length in line_lengths:
    dataset1 = [np.empty(line_length, dtype=complex) for _ in range(N)]
    for line in dataset1:
        line.real = np.random.uniform(0, 1000, line_length)
        line.imag = np.random.uniform(0, 1000, line_length)

    times_basic.append(timeit.timeit(lambda: translate_basic(dataset1, offset), number=20))
    times_threaded.append(
        timeit.timeit(lambda: translate_threaded(dataset1, offset), number=20))

thread_pool.close()
thread_pool.terminate()

plt.plot(line_lengths, times_basic, '.-r')
plt.plot(line_lengths, times_threaded, '.-b')
plt.show()
image

Pivot point is ~3.5k points per lines.