Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Labels
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Commits
Open sidebar
nexedi
cython
Commits
8f9485cc
Commit
8f9485cc
authored
Mar 17, 2018
by
gabrieldemarmiesse
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Made all the necessary changes.
parent
c6daaccf
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
63 additions
and
29 deletions
+63
-29
docs/src/tutorial/cython_tutorial.rst
docs/src/tutorial/cython_tutorial.rst
+63
-29
No files found.
docs/src/tutorial/cython_tutorial.rst
View file @
8f9485cc
...
...
@@ -142,15 +142,23 @@ Now, let's dig into the core of the function::
cdef int p[1000]
Lines 2 and 3 use the ``cdef`` statement to define some local C variables.
The result is put in ``p``, it will be converted to a python list at the end
of the function (line 22). ::
The result is stored in the C array ``p`` during processing,
and will be copied into a Python list at the end (line 22).
.. NOTE:: You cannot create very large arrays in this manner, because
they are allocated on something called the stack.
To request larger arrays,
or even arrays with a length only known at runtime
you can learn how to use :ref:`Python arrays<array-array>`
or :ref:`NumPy arrays<memoryviews>` with Cython.
::
if nb_primes > 1000:
nb_primes = 1000
As in C, declaring a static array requires knowing the size at compile time.
We make sure the user doesn't set a value above 1000 (or we
'll have a nice
segmentation fault, just like in C). ::
We make sure the user doesn't set a value above 1000 (or we
would have a
segmentation fault, just like in C).
::
len_p = 0 # The number of elements in p
n = 2
...
...
@@ -171,10 +179,9 @@ You will notice the way we iterate over the ``p`` C array. ::
for i in p[:len_p]:
The loop gets translated into C code transparently. No more ugly C for loops!
Well don't forget how to loop in C style with integers yet, you might need it someday.
If you don't use ``:len_p`` then Cython will loop over the 1000 elements of
the array (it won't go out of bounds and give a segmentation fault). ::
The loop gets translated into C code transparently. As if it was a Python list
or a NumPy array. If you don't use ``[:len_p]`` then Cython will loop
over the 1000 elements of the array. ::
# If no break occurred in the loop
else:
...
...
@@ -184,29 +191,29 @@ the array (it won't go out of bounds and give a segmentation fault). ::
If no breaks occurred, it means that we found a prime, and the block of code
after the ``else`` line 16 will be executed. We add the prime found to ``p``.
If you find having a
else after a for loop
strange, just know that it's a
hidden secret of the python syntax, and actually doesn't exist in C!
But since Cython is made to be written with the Python syntax, it'll
work out, as if you wrote Python code
, but at C speed in this case.
If the
for...else
syntax still confuses you, see this excellent
If you find having a
n ``else`` after a ``for-loop``
strange, just know that it's a
lesser known features of the Python language of the python syntax, and
actually doesn't exist in C! But since Cython is made to be written with the
Python syntax, it'll work out
, but at C speed in this case.
If the
``for-else``
syntax still confuses you, see this excellent
`blog post <https://shahriar.svbtle.com/pythons-else-clause-in-loops>`_. ::
# Let's put the result in a python list:
result_as_list = [prime for prime in p[:len_p]]
return result_as_list
Line 22, before returning the result, we need to co
nvert
our C array into a
Python list, because Python can't read C arrays.
Note that Cython handle
for you the conversion of quite some types between C and Python (you can
see exactly which :ref:`here
<type-conversion>`. But not C arrays. We can trick
Line 22, before returning the result, we need to co
py
our C array into a
Python list, because Python can't read C arrays.
Cython can automatically
convert many C types from and to Python types, as described in the
documentation on :ref:`type conversion
<type-conversion>`. But not C arrays. We can trick
Cython into doing it because Cython knows how to convert a C int to a Python int.
By doing a list comprehension, we "cast" each C int prime from
p
into a Python int.
By doing a list comprehension, we "cast" each C int prime from
``p``
into a Python int.
You could have also iterated manually over the C array and used
``result_as_list.append(prime)``, the result would have been the same.
You'll notice we declare a Python list exactly the same way it would be in Python.
Because the variable ``result_as_list`` hasn't been
given a type, it is assumed to
hold a Python object.
Because the variable ``result_as_list`` hasn't been
explicitly declared with a type,
it is assumed to
hold a Python object.
Finally, at line 18, a normal
Python return statement returns the result list.
...
...
@@ -222,14 +229,18 @@ See, it works! And if you're curious about how much work Cython has saved you,
take a look at the C code generated for this module.
It is always good to check where is the Python interaction in the code with the
``annotate=True`` parameter in ``cythonize()``. Let's see:
Cython has a way to visualise where interaction with Python objects and
Python's C-API is taking place. For this, pass the
``annotate=True`` parameter to ``cythonize()``. It produces a HTML file. Let's see:
.. figure:: htmlreport.png
If a line is white, it means that the code generated doesn't interact
with Python, so will run fast. The darker the yellow, the more Python
interaction there is. Those yellow lines will run slower.
The function declaration and return use the Python interpreter so it makes
sense for those lines to be yellow. Same for the list comprehension because
it involves the creation of a
p
ython object. But the line ``if n % i == 0:``, why?
it involves the creation of a
P
ython object. But the line ``if n % i == 0:``, why?
We can examine the generated C code to understand:
.. figure:: python_division.png
...
...
@@ -257,20 +268,43 @@ Let's write the same program, but Python-style::
n += 1
return p
It is also possible to take a plain ``.py`` file and to compile it with Cython.
Let's take ``primes_python``, change the function name to ``primes_python_compiled`` and
compile it with Cython (without changing the code). We will also change the name of the
file to ``example_py_cy.py`` to differentiate it from the others.
Now the ``setup.py`` looks like this::
from distutils.core import setup
from Cython.Build import cythonize
setup(
ext_modules=cythonize(['example.pyx', # has the primes() function
'example_py_cy.py'], # has the primes_python_compiled() function
annotate=True), # produces the html annotation file
)
Now we can ensure that those two programs output the same values::
>>> primes_python(500) == primes(500)
>>> primes_python(1000) == primes(1000)
True
>>> primes_python_compiled(1000) == primes(1000)
True
It's possible to compare the speed now::
>>> %timeit primes_python(500)
5.8 ms ± 178 µs per loop (mean ± std. dev. of 7 runs, 100 loops each) ::
python -m timeit -s 'from example_py import primes_python' 'primes_python(1000)'
10 loops, best of 3: 23 msec per loop
python -m timeit -s 'from example_py_cy import primes_python_compiled' 'primes_python_compiled(1000)'
100 loops, best of 3: 11.9 msec per loop
>>> %timeit primes(500)
502 µs ± 2.22 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
python -m timeit -s 'from example import primes' 'primes(1000)'
1000 loops, best of 3: 1.65 msec per loop
The Cython version is 11 times faster than the Python version! What could explain this?
The cythonize version of ``primes_python`` is 2 times faster than the Python one,
without changing a single line of code.
The Cython version is 13 times faster than the Python version! What could explain this?
Multiple things:
* In this program, very little computation happen at each line.
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment