Python 词典分配使Cython崩溃

Python 词典分配使Cython崩溃,python,cython,Python,Cython,下面的cython代码由于word_idxs[token]=row语句而崩溃。如果我去掉那句话,一切都会好起来的。以下是我的观察结果 当以不同的文件作为参数时,代码工作正常 我尝试打印token,程序在不同时间因token的不同值而崩溃(导致错误的不是特定单词) 我尝试分配word_idxs[row]=row,但错误仍然存在。所以我认为这个错误与字符串无关 如果我一直分配给同一个键,则不会发生错误。例如:word_idxs['constant']=row 如果我删除cmatrix[row,col

下面的cython代码由于
word_idxs[token]=row
语句而崩溃。如果我去掉那句话,一切都会好起来的。以下是我的观察结果

  • 当以不同的文件作为参数时,代码工作正常
  • 我尝试打印
    token
    ,程序在不同时间因
    token
    的不同值而崩溃(导致错误的不是特定单词)
  • 我尝试分配
    word_idxs[row]=row
    ,但错误仍然存在。所以我认为这个错误与字符串无关
  • 如果我一直分配给同一个键,则不会发生错误。例如:
    word_idxs['constant']=row
  • 如果我删除
    cmatrix[row,col]=fval
    ,那么一切都会正常工作
  • 我是Cython的新手,如果我做了一些根本错误的事情,请指出

     def cload(self, file_path, int dim, long vocab_size):
        print("Loading")
        cdef:
            unsigned int row = 0
            int col = 0
            float [:,:] cmatrix
            cdef dict word_idxs = {}
            char* token
            char* line
    
        matrix = np.zeros([vocab_size, dim], dtype=np.dtype('f'))
        cmatrix = matrix
    
        with open(file_path, 'rb') as f:
            for line in f:
                token = strtok(line, ' \n')
                print(row, token)
    
                word_idxs[token] = row
    
                for col in range(dim) :
                    val = strtok(NULL,' ')
                    fval = atof(val)
                    cmatrix[row, col] = fval
                row += 1
    

    对我来说,最明显的问题是,对
    令牌
    val
    的输出没有错误检查。如果
    strtok
    到达字符串末尾,而您只是不处理这个问题,那么它可以是
    NULL
    。由于缺乏可验证的例子,很难知道实际问题是什么

    @ead在评论中指出了几个问题:

  • Python字符串应该是不可变的,但是strtok会修改给定的指针。这不太可能导致您看到的崩溃,但可能会导致Python出现问题

  • line
    很可能是一个无效的指针(因为它所基于的Python对象从未保留过)

  • 我认为这些问题可以通过以下方式解决

    cdef char* line_ptr
    for line in f: # line IS NOT TYPED
      line_ba = bytearray(line) # bytearray is mutable - changing it is fine
      line_ptr = line_ba # line_ptr is valid as long as line_ba exists
    

    您的代码和我建议的替换代码都在Python和C字符串之间进行了大量转换,这从来都不是非常快(而且很难做到正确)。这看起来是用Python编写的最简单的一种方法——我怀疑您是否真的从C调用中获益。

    我投了反对票,因为这不是一个最小的、完整的、可验证的示例。用你提供的代码复制你的bug是不可能的。我认为strtok的
    line
    改变了
    line
    -它把
    \0
    放在需要的地方。然而,这有可能改变不可变的Python字节。我想在大多数情况下不会发生这种情况,因为
    line
    是一个悬空的指针-没有任何东西保存原始bytes对象的引用,因此它可能在此时已被破坏-因此崩溃(尽管不是100%确定)。然而,这对于内存中的字节对象来说是一个问题。使用python进行解析是一个非常好的建议。看看C是否有可能更快,这将是一件很有趣的事情。@ead关于更改
    的说法是正确的。这是另一场即将发生的灾难,但确实使我的第二点无效。关于
    和悬垂的指针,你也是对的-我没有注意到。我怀疑C可以更快,但我非常不喜欢使用C字符串,所以不会是我让它更快:)