mirror of
https://github.com/speice-io/release-the-gil
synced 2024-12-21 22:28:21 -05:00
Fibonacci and double-unlock examples
This commit is contained in:
commit
29edf9cc8f
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
*.c
|
||||||
|
*.so
|
19
setup.py
Normal file
19
setup.py
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
from setuptools import setup, find_packages
|
||||||
|
from Cython.Build import cythonize
|
||||||
|
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name="release-the-gil",
|
||||||
|
version="0.1",
|
||||||
|
author="Bradlee Speice",
|
||||||
|
author_email="bradlee@speice.io",
|
||||||
|
description="Basic examples of parallelism in Python",
|
||||||
|
url="https://github.com/speice-io/release-the-gil",
|
||||||
|
packages=find_packages(),
|
||||||
|
ext_modules=cythonize("src/*.pyx"),
|
||||||
|
install_requires=[
|
||||||
|
"Cython",
|
||||||
|
"numba",
|
||||||
|
"texttable"
|
||||||
|
],
|
||||||
|
)
|
0
src/__init__.py
Normal file
0
src/__init__.py
Normal file
4
src/double_unlock.py
Normal file
4
src/double_unlock.py
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
from double_unlock_cython import unlock
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unlock()
|
8
src/double_unlock_cython.pyx
Normal file
8
src/double_unlock_cython.pyx
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
cdef void _unlock() nogil:
|
||||||
|
with nogil:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def unlock():
|
||||||
|
with nogil:
|
||||||
|
_unlock()
|
102
src/fibonacci.py
Normal file
102
src/fibonacci.py
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
import argparse
|
||||||
|
from collections import defaultdict
|
||||||
|
from threading import Thread
|
||||||
|
from time import monotonic_ns
|
||||||
|
from typing import List, DefaultDict
|
||||||
|
|
||||||
|
from numba import jit
|
||||||
|
from texttable import Texttable
|
||||||
|
|
||||||
|
from fibonacci_cython import cython_gil, cython_nogil
|
||||||
|
|
||||||
|
|
||||||
|
@jit(nopython=True, nogil=True)
|
||||||
|
def numba_nogil(n: int) -> int:
|
||||||
|
if n <= 1:
|
||||||
|
return n
|
||||||
|
|
||||||
|
a = 0
|
||||||
|
b = 1
|
||||||
|
|
||||||
|
c = a + b
|
||||||
|
for _i in range(2, n):
|
||||||
|
a = b
|
||||||
|
b = c
|
||||||
|
c = a + b
|
||||||
|
|
||||||
|
return c
|
||||||
|
|
||||||
|
|
||||||
|
@jit(nopython=True)
|
||||||
|
def numba_gil(n: int) -> int:
|
||||||
|
if n <= 1:
|
||||||
|
return n
|
||||||
|
|
||||||
|
a = 0
|
||||||
|
b = 1
|
||||||
|
|
||||||
|
c = a + b
|
||||||
|
for _i in range(2, n):
|
||||||
|
a = b
|
||||||
|
b = c
|
||||||
|
c = a + b
|
||||||
|
|
||||||
|
return c
|
||||||
|
|
||||||
|
|
||||||
|
def main(n: int = 1_000_000_000):
|
||||||
|
# Pre-compile the numba variants
|
||||||
|
numba_nogil(15)
|
||||||
|
numba_gil(15)
|
||||||
|
|
||||||
|
functions = [cython_gil, cython_nogil, numba_gil, numba_nogil]
|
||||||
|
names = ["cython_gil", "cython_nogil", "numba_gil", "numba_nogil"]
|
||||||
|
results_single: List[str] = []
|
||||||
|
results: DefaultDict[str, List[str]] = defaultdict(list)
|
||||||
|
|
||||||
|
for i, t1_function in enumerate(functions):
|
||||||
|
t1_name = names[i]
|
||||||
|
|
||||||
|
start = monotonic_ns()
|
||||||
|
t1_function(n)
|
||||||
|
end = monotonic_ns()
|
||||||
|
runtime = str((end - start) / float(1_000_000)) + "ms"
|
||||||
|
results_single.append(runtime)
|
||||||
|
|
||||||
|
for j, t2_function in enumerate(functions):
|
||||||
|
t1 = Thread(target=t1_function, args=[n])
|
||||||
|
t2 = Thread(target=t2_function, args=[n])
|
||||||
|
|
||||||
|
# While there's overhead in the thread start/join calls unrelated to
|
||||||
|
# actual runtime, it's pretty small relative to total runtime
|
||||||
|
start = monotonic_ns()
|
||||||
|
|
||||||
|
# The order in which we start threads matters!
|
||||||
|
t1.start()
|
||||||
|
t2.start()
|
||||||
|
t1.join()
|
||||||
|
t2.join()
|
||||||
|
end = monotonic_ns()
|
||||||
|
|
||||||
|
runtime = str((end - start) / float(1_000_000)) + "ms"
|
||||||
|
results[t1_name].append(runtime)
|
||||||
|
|
||||||
|
table = Texttable()
|
||||||
|
table.header(names)
|
||||||
|
table.add_row(results_single)
|
||||||
|
print(table.draw())
|
||||||
|
|
||||||
|
table = Texttable()
|
||||||
|
table.header([""] + names)
|
||||||
|
for main_name, results in results.items():
|
||||||
|
table.add_row([main_name] + results)
|
||||||
|
|
||||||
|
print(table.draw())
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument('-n', help='Fibonacci number to calculate', default=1_000_000_000)
|
||||||
|
cmdline = parser.parse_args()
|
||||||
|
|
||||||
|
main(cmdline.n)
|
24
src/fibonacci_cython.pyx
Normal file
24
src/fibonacci_cython.pyx
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
cdef unsigned long fibonacci(unsigned long n) nogil:
|
||||||
|
if n <= 1:
|
||||||
|
return n
|
||||||
|
|
||||||
|
cdef unsigned long a = 0, b = 1, c = 0
|
||||||
|
|
||||||
|
c = a + b
|
||||||
|
for _i in range(2, n):
|
||||||
|
a = b
|
||||||
|
b = c
|
||||||
|
c = a + b
|
||||||
|
|
||||||
|
return c
|
||||||
|
|
||||||
|
|
||||||
|
def cython_nogil(unsigned long n):
|
||||||
|
with nogil:
|
||||||
|
value = fibonacci(n)
|
||||||
|
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
def cython_gil(unsigned long n):
|
||||||
|
return fibonacci(n)
|
Loading…
Reference in New Issue
Block a user