Skip to content

Commit 3c0c878

Browse files
committed
Add a cython test to give perspective on relative ease/performance
The cython implementation is about 2x slower than the Rust implementation, but it's not clear if the slice in the cython call is actually doing a copy of the entire memory-area or just doing a simple reference of the memory. Note that the cython implementation doesn't build a proper module with setup.py, it just uses the command-line cythonize operation to produce a quick-and-dirty extension.
1 parent d0d6c42 commit 3c0c878

5 files changed

Lines changed: 43 additions & 1 deletion

File tree

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,12 @@
55
/pyext-myclib/myclib.py
66
/pyext-myclib/myclib_wrap.c
77
/pyext-myclib/_myclib.cpython*
8+
/pyext-mycythonlib/*.so
9+
/pyext-mycythonlib/*.c
10+
/pyext-mycythonlib/*.html
811
.cache
912
.benchmarks
1013
__pycache__
1114
myrustlib.so
15+
mycythonlib*.so
1216
/pyext-myrustlib/.gitignore

Makefile

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
.PHONY: clean clean-test clean-pyc clean-build docs help
1+
.PHONY: clean clean-test clean-pyc clean-build docs help test-python test-rust test-c test-cython compile-cython compile-rust compile-c
22

33
clean: clean-build clean-pyc clean-test ## remove all build, test, coverage and Python artifacts
44

55
clean-build: ## remove build artifacts
66
rm -fr build/
77
rm -fr dist/
88
rm -fr .eggs/
9+
rm -fr .compiled
910
find . -name '*.egg-info' -exec rm -fr {} +
1011
find . -name '*.egg' -exec rm -f {} +
1112

@@ -32,6 +33,9 @@ test-rust: ## run tests quickly with the default Python
3233
test-c: ## run tests quickly with the default Python
3334
py.test -v -s doubles_with_c_swig.py
3435

36+
test-cython: # run tests quickly with the default Python
37+
py.test -v -s doubles_with_cython.py
38+
3539
test-all: ## run tests quickly with the default Python
3640
py.test -v -s doubles_all.py
3741

@@ -41,3 +45,14 @@ compile-rust: ## compile new rust lib
4145

4246
compile-c: ## compile new c lib
4347
@cd pyext-myclib;python3 setup.py build_ext -i
48+
49+
compile-cython: ## compile new cython lib
50+
@cd pyext-mycythonlib;cythonize -a -i mycythonlib.pyx
51+
@cp pyext-mycythonlib/mycythonlib*.so ./
52+
53+
compile-all: compile-rust compile-c compile-cython
54+
55+
.compiled: compile-all
56+
touch .compiled
57+
58+
test: compile-all test-all

doubles_all.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import itertools
55
import numpy as np
66
import myrustlib # <-- Importing Rust Implemented Library
7+
import mycythonlib # <-- Importing Cython Implemented Library
78

89
import sys
910
sys.path.append('./pyext-myclib')
@@ -101,3 +102,6 @@ def test_c_swig_bytes_once(benchmark):
101102

102103
# def test_rust_regex(benchmark):
103104
# print(benchmark(myrustlib.count_doubles_regex, val))
105+
106+
def test_cython(benchmark):
107+
print(benchmark(mycythonlib.count_doubles, val))

pyext-mycythonlib/mycythonlib.pyx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
def count_doubles( unicode source ):
2+
"""Count number of doubles in a (unicode) string
3+
4+
A double is counted for every character where the
5+
character at the previous index in the string is
6+
the same character as the current character. Thus
7+
the string 'aaa' has two doubles.
8+
"""
9+
cdef Py_ssize_t count
10+
count = 0
11+
if not source:
12+
return count
13+
char = source[0]
14+
for next_char in source[1:]:
15+
if next_char == char:
16+
count += 1
17+
char = next_char
18+
return count

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
pytest
22
pytest-benchmark
33
numpy
4+
cython

0 commit comments

Comments
 (0)