Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to release the GIL in Cython for a multithreaded C++ class?

I have a C++ class with some methods that use std::thread that I'm making accessible to Python via Cython. Do you know where in my Cython code I'd want to put the nogill directive? Would I want to put it when I declare the class methods or when I create a Cython wrapper class? I've used the example class from the Cython docs below:

Declaring the class:

cdef extern from "Rectangle.h" namespace "shapes":
    cdef cppclass Rectangle:
        Rectangle() except +
        Rectangle(int, int, int, int) except +
        int x0, y0, x1, y1
        int getArea()
        void getSize(int* width, int* height)
        void move(int, int)

Cython wrapper class:

cdef class PyRectangle:
    cdef Rectangle c_rect      # hold a C++ instance which we're wrapping
    def __cinit__(self, int x0, int y0, int x1, int y1):
        self.c_rect = Rectangle(x0, y0, x1, y1)
    def get_area(self):
        return self.c_rect.getArea()
    def get_size(self):
        cdef int width, height
        self.c_rect.getSize(&width, &height)
        return width, height
    def move(self, dx, dy):
        self.c_rect.move(dx, dy)
like image 798
Jack Simpson Avatar asked Mar 13 '17 12:03

Jack Simpson


People also ask

Does Cython have a Gil?

Cython allows you to release the GIL. That means that you can do multi-threading in at least 2 ways: Directly in Cython, using OpenMP with prange. Using e.g. joblib with a multi-threading backend (the parts of your code that will be parallelized are the parts that release the GIL)

Is Cython multithreaded?

In this chapter we will learn about Cython's multithreading features to access thread-based parallelism. Our focus will be on the prange Cython function, which allows us to easily transform serial for loops to use multiple threads and tap into all available CPU cores.

Does Cython use C or C++?

Cython is a programming language that blends Python with the static type system of C and C++. cython is a compiler that translates Cython source code into efficient C or C++ source code. This source can then be compiled into a Python extension module or a standalone executable.

Can you use C++ in Cython?

Cython has native support for most of the C++ language. Specifically: C++ objects can be dynamically allocated with new and del keywords. C++ objects can be stack-allocated.


1 Answers

You probably don't actually need to use nogil. The GIL only stops multiple Python threads being run simulatenously. However, given you're using C++ threads they can quite happily run in the background irrespective of the GIL, provided they don't try to use PyObjects or run Python code. So my suspicion is that you've misunderstood the GIL and you can get away with not thinking about it.

However, assuming that you do actually want to release it, you need to do 2 things:

  1. Mark the C++ functions as nogil to tell Cython that they don't need the GIL. Note that this doesn't actually release it - it just lets Cython know it isn't a problem if it is released:

    cdef cppclass Rectange:
       Rectangle(int, int, int, int) nogil except +
       int getArea() nogil
       # ...
    
  2. Use with nogil: blocks in your Cython wrapper class to mark the areas where the GIL is actually released.

    cdef class PyRectangle:
        # ...
        def __cinit__(self, int x0, int y0, int x1, int y1):
            with nogil:
                self.c_rect = Rectangle(x0, y0, x1, y1)
        def get_area(self):
            cdef int result
            with nogil:
                result = self.c_rect.getArea()
            return result
    

    get_area becomes slightly more complicated since the return statement can't exist inside the with nogil block since it involves generating a Python object.

like image 140
DavidW Avatar answered Nov 10 '22 19:11

DavidW