最近部分功能在用golang build成c库,然后让python ctypes调用。
###实现过程
- 根据*C.char, [][]byte生成一块内存空间
- 遍历[][]byte,根据index, *C.char的尺寸来做指针运算
- 在适当的位置进行赋值
- 做类型转换
- cyptes中设置restype = ctypes.POINTER(ctypes.c_char_p)
- ctypes中再传一 个ctypes.c_int的指针进去, 告诉python有多少个字符串元素
golang
//export PyFindAll
func PyFindAll(re_rule *C.char, content *C.char, total *C.int, content_length C.int) **C.char {
go_re_rule, go_content := C.GoString(re_rule), C.GoBytes(unsafe.Pointer(content), content_length)
go_result := FindAll(go_re_rule, go_content)
var b *C.char
ptr_size := unsafe.Sizeof(b) // 计算出一个char指针的长度
ptr := C.malloc(C.size_t(len(go_result)) * C.size_t(ptr_size)) // 申请一块空间, 长度为go_result个数 * char指针的长度
// defer C.free(unsafe.Pointer(content))
// defer C.free(ptr)
for index := 0; index < len(go_result); index++ {
element := (**C.char)(unsafe.Pointer(uintptr(ptr) + uintptr(index)*ptr_size)) // 移位操作*char
*element = C.CString(string(go_result[index]))
}
*total = (C.int)(len(go_result))
return (**C.char)(ptr)
}
python
import time
content = open("index.html", "rb").read()
import ctypes
lib = ctypes.CDLL("re.so")
lib.PyFindAll.restype = ctypes.POINTER(ctypes.c_char_p)
#lib.PyFindAll.argtypes = [ctypes.c_char_p, ctypes.c_char_p, ctypes.POINTER(ctypes.c_int)]
total = ctypes.c_int(0)
content_length = ctypes.c_int(len(content))
def test():
c_result = lib.PyFindAll('<div id="(footer)"[\s|\S]+?Build version\s+?(.+?)[\s|\<]', content, ctypes.pointer(total), content_length)
print([ c_result[i] for i in range(total.value)])
if __name__ == "__main__":
begin = time.time()
for i in range(1000):
test()
print(time.time() - begin)