在Cython中哪些C函数不需要gil?

时间:2015-10-27 12:58:20

标签: python cython

我尝试编译以下Cython代码,该代码使用C函数进行文件操作:

import tempfile
from libc.stdio cimport *

cdef extern from "stdio.h":
    FILE *fopen(const char *, const char *)
    int fclose(FILE *)
    size_t fwrite(const void *, size_t, size_t, FILE *)
    ssize_t getline(char **, size_t *, FILE *)

def run_io():
    cdef int ntasks
    cdef int i
    cdef string dump = "Some string"
    cdef string content = ""
    cdef char* fname
    cdef FILE* cfile
    cdef char* line = NULL
    cdef size_t l = 0
    tmpfile = tempfile.NamedTemporaryFile('w+')
    fname = tmpfile.name.encode("UTF-8")
    with nogil:
        cfile = fopen(fname, "wb")
        #fwrite(dump.data(), 1, dump.size(), cfile)
        #fclose(cfile)
        #cfile = fopen(fname, "rb")
        #if getline(&line, &l, cfile) == -1:
            #break
        #else:
            #printf("%s", line)
        fclose(cfile)
    tmpfile.close()

但是,我收到以下错误:

Error compiling Cython file:
------------------------------------------------------------
...
        #cfile = fopen(fname, "rb")
        #if getline(&line, &l, cfile) == -1:
            #break
        #else:
            #printf("%s", line)
        fclose(cfile)
             ^
------------------------------------------------------------

test.pyx:31:14: Calling gil-requiring function not allowed without gil

我认为只有python个函数需要gil,但不会导入C个函数。然而,似乎并非如此。

因此,我的问题是:

  1. Cython没有GIL
  2. 可以使用哪些C函数
  3. 如何在没有GIL的情况下进行文件读/写?

1 个答案:

答案 0 :(得分:7)

您正在使用

声明来自libc.stdio的声明
cdef extern from "stdio.h" nogil:

您自己的定义没有nogil。要回答标题中的问题:只有Python / C API函数需要gil。

这是您的代码,正确导入并修剪任何不相关的内容:

import tempfile
from libc.stdio cimport fopen, fclose, fwrite, getline, FILE
from libcpp.string cimport string

def run_io():
    cdef string dump = b"Some string"
    tmpfile = tempfile.NamedTemporaryFile('w+')
    cdef bytes py_fname = tmpfile.name.encode("UTF-8")
    cdef char* fname = py_fname
    cdef FILE* cfile
    with nogil:
        cfile = fopen(fname, "wb")
        fclose(cfile)
    tmpfile.close()

以下内容有助于确保tmpfile.name.encode返回的临时的生命周期延长。

cdef bytes py_fname = tmpfile.name.encode("UTF-8")
cdef char* fname = py_fname

使用

编译时不会出错
cython -3 --cplus my_mod.pyx
g++ my_mod.cpp -shared -o my_mod.so $(python3.4 --cflags --ldflags)