Write programs with cython for higher performance

My favorite programming language is Python, because its code is elegant and practical. However, it's slower than most other languages in terms of speed. Most people think that speed and ease of use are conflicting. Writing C code is really painful. Cython tries to eliminate this conflict, allowing you to have both the Python syntax and C data types and functions—both of which are excellent in their own right. I am by no means an expert in this area, but this is my first real experience with Cython. EDIT: Based on some feedback I received, there was a bit of confusion. Cython is used to generate C extensions rather than standalone programs. All acceleration is done for a function within an existing Python application. There's no need to rewrite the entire application in C or Lisp, nor is there any handwritten C extension. It's just a simple way to integrate C's speed and C data types into Python functions. Now we can say that we can make the following great_circle function faster. The so-called great_circle problem involves calculating the distance between two points on the surface of the Earth: Import math Def great_circle(lon1, lat1, lon2, lat2): Radius = 3956 # miles x = math.pi / 180.0 a = (90.0 - lat1) * (x) b = (90.0 - lat2) * (x) theta = (lon2 - lon1) * (x) c = math.acos((math.cos(a) * math.cos(b)) + (math.sin(a) * math.sin(b) * math.cos(theta))) Return radius * c Let’s call it 500,000 times and measure its time: Import timeit Lon1, lat1, lon2, lat2 = -72.345, 34.323, -61.823, 54.826 Num = 500000 t = timeit.Timer("p1.great_circle(%f,%f,%f,%f)" % (lon1, lat1, lon2, lat2), "import p1") Print "Pure python function", t.timeit(num), "sec" It takes about 2.2 seconds. That's too slow! Let's try rewriting it quickly with Cython and see if there's a difference: Import math Def great_circle(float lon1, float lat1, float lon2, float lat2): cdef float radius = 3956.0 cdef float pi = 3.14159265 cdef float x = pi / 180.0 cdef float a, b, theta, c a = (90.0 - lat1) * (x) b = (90.0 - lat2) * (x) theta = (lon2 - lon1) * (x) c = math.acos((math.cos(a) * math.cos(b)) + (math.sin(a) * math.sin(b) * math.cos(theta))) Return radius * c Note that we still import math—Cython allows mixing Python and C data types to some extent. The conversion is automatic, but not without cost. What we did in this example is to define a Python function, declare its input parameters as float type, and declare all variables as C floating-point data types. The calculation part still uses Python's math module. Now we need to convert it to C code and compile it into a Python extension. The best way to do this is to write a setup.py script, but for now, we'll do it manually to understand the process: # This will create a c1.c file - the C source code to build a Python extension Cython c1.pyx # Compile the object file Gcc -c -fPIC -I/usr/include/python2.5 c1.c # Link it into a shared library Gcc -shared c1.o -o c1.so Now you should have a c1.so (or .dll) file that can be imported by Python. Run it now: t = timeit.Timer("c1.great_circle(%f,%f,%f,%f)" % (lon1, lat1, lon2, lat2), "import c1") Print "Cython function (still using Python math)", t.timeit(num), "sec" It takes about 1.8 seconds. There's no significant performance boost as we initially expected. Using the Python math module is the bottleneck. Now let's replace it with the C standard library: Cdef extern from "math.h": Float cosf (float theta) Float sinf (float theta) Float acosf (float theta) Def great_circle(float lon1, float lat1, float lon2, float lat2): cdef float radius = 3956.0 cdef float pi = 3.14159265 cdef float x = pi / 180.0 cdef float a, b, theta, c a = (90.0 - lat1) * (x) b = (90.0 - lat2) * (x) theta = (lon2 - lon1) * (x) c = acosf((cosf(a) * cosf(b)) + (sinf(a) * sinf(b) * cosf(theta))) Return radius * c Corresponding to import math, we use cdef extern to declare the functions from the specified header file (here is math.h using the C standard library). We replaced the costly Python functions, then built a new shared library and retested it. t = timeit.Timer("c2.great_circle(%f,%f,%f,%f)" % (lon1, lat1, lon2, lat2), "import c2") Print "Cython function (using trig function from math.h)", t.timeit(num), "sec" Now it's 0.4 seconds—5 times faster than pure Python functions. What other methods can we use to increase the speed? c2.great_circle() is still a Python function call, which means it generates the overhead of the Python API (building parameter tuples, etc.). If we can write a pure C function, we might be able to speed up further. Cdef extern from "math.h": Float cosf (float theta) Float sinf (float theta) Float acosf (float theta) Cdef float _great_circle(float lon1, float lat1, float lon2, float lat2): cdef float radius = 3956.0 cdef float pi = 3.14159265 cdef float x = pi / 180.0 cdef float a, b, theta, c a = (90.0 - lat1) * (x) b = (90.0 - lat2) * (x) theta = (lon2 - lon1) * (x) c = acosf((cosf(a) * cosf(b)) + (sinf(a) * sinf(b) * cosf(theta))) Return radius * c Def great_circle(float lon1, float lat1, float lon2, float lat2, int num): cdef int i cdef float x For i from 0 <= i < num: x = _great_circle(lon1, lat1, lon2, lat2) Return x Note that we still have a Python function (def) that takes an extra argument num. The loop in this function uses for i from 0 <= i < num: instead of Pythonic, but much slower for i in range(num):. The real calculation is done in the C function (cdef), which returns the float type. This version is only 0.2 seconds—10 times faster than the original Python function. To prove that what we have done is optimized enough, you can write a small application in pure C and then measure the time: #include #include #define NUM 500000 Float great_circle(float lon1, float lat1, float lon2, float lat2){ Float radius = 3956.0; Float pi = 3.14159265; Float x = pi / 180.0; Float a, b, theta, c; a = (90.0 - lat1) * (x); b = (90.0 - lat2) * (x); theta = (lon2 - lon1) * (x); c = acos((cos(a) * cos(b)) + (sin(a) * sin(b) * cos(theta))); Return radius * c; } Int main(){ Int i; Float x; For (i = 0; i <= NUM; i++) x = great_circle(-72.345, 34.323, -61.823, 54.826); Printf("%f", x); } Compile it with gcc -lm -octest ctest.c and test with time ./ctest... for about 0.2 seconds. This gives me confidence that my Cython extension is also very efficient relative to my C code (this is not to say that my C programming ability is very weak). How much performance can be optimized with Cython usually depends on how many loops, numeric operations, and Python function calls, which slow down the program. Some people have reported a 100 to 1000 times speed increase in some cases. As for other tasks, it may not be so useful. Keep this in mind before frantically rewriting Python code with Cython: “We should forget small efficiency, and premature optimization is the root of all evil, 97% of cases.” – Donald Knuth In other words, write the program in Python first and see if it meets your needs. In most cases, its performance is good enough... but sometimes it feels slow, then use the parser to find the bottleneck function, then rewrite it with Cython, and you'll get better performance soon.

Submarine Cable

Submarine Cable,Undersea Cable,Submarine Fiber Optic Cable,Ocean Fiber Optic Cable

HENAN QIFAN ELECTRIC CO., LTD. , https://www.hnqifancable.com