最近部分功能在用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)