如何有效地将大字符串从 Python 传递到 C++ 扩展方法?
Posted
技术标签:
【中文标题】如何有效地将大字符串从 Python 传递到 C++ 扩展方法?【英文标题】:How to pass a large string from Python to a C++ extension method efficiently? 【发布时间】:2018-12-31 18:32:34 【问题描述】:简介
我正在处理需要处理大量文本数据的项目。许多相当大(数百 MB)的文本文件。 python是必需的(不要问为什么)。我想使用 C++ 扩展来提高性能。我决定选择 SWIG。我有一个模式匹配算法,它比通常的 python "string".find("pattern") 快得多。当我看到它用作 python 扩展时要慢得多时,我感到很惊讶。它不应该发生。我想我很接近找到原因,但需要您的帮助。
问题
现在,我用包含类的方法编写了一个简单的扩展,它什么都不做(只需将字符串作为参数并返回数值(函数中不进行任何处理):
nothing.h:
#ifndef NOTHING_H
#define NOTHING_H
#include <string.h>
#include <iostream>
using namespace std;
class nothing
protected:
int zm = 5;
public:
virtual int do_nothing(const char *empty);
;
#endif
nothing.cpp
#include "nothing.h"
int nothing::do_nothing(const char *empty)
return this->zm;
nothing.i
%module nothing
%include <std_string.i>
using std::string;
using namespace std;
%
#include "nothing.h"
%
class nothing
protected:
int zm = 5;
public:
virtual int do_nothing(const char *empty);
;
test.py
import nothing
import time
data = ""
with open('../hugefile', 'rb') as myfile:
data=myfile.read().decode(errors='replace')
n = len(data)
zm = nothing.nothing()
start = time.time()
res = zm.do_nothing(data)
end = time.time()
print("Nothing time: ".format(end - start))
zm = nothing.nothing()
start = time.time()
res = data.find("asdasdasd")
end = time.time()
print("Find time : ".format(end - start))
编译步骤:
swig -c++ -py3 -extranative -python nothing.i
g++ -fpic -lstdc++ -O3 -std=c++11 -c nothing.cpp nothing_wrap.cxx -I/usr/include/python3.7m
g++ -shared nothing.o nothing_wrap.o -o _nothing.so
输出:
$ python3 test.py
Nothing time: 0.3149874210357666
Find time : 0.09926176071166992
如您所见,尽管没有什么比 find() 快得多,但它却慢了很多!
知道这是否可以以某种方式解决吗?对我来说,数据似乎被转换或复制了。
为什么我认为整个数据都被复制了?因为如果稍微将函数 do_nothing() 更改为(我省略了标题):
int nothing::do_nothing() // removed the argument
return this->zm;
那么结果如预期:
$ python3 test.py
Nothing time: 4.291534423828125e-06
Find time : 0.10114812850952148
【问题讨论】:
Python 必须在调用之前创建一个 unmanaged 对象/char *
/字符串(是的,这意味着分配和复制数据)。
我想知道是否使用 non-Unicode 'string' / byte-array(所有 Python 3 字符串都是 Unicode,这是对 Python 2.x 的更改)是否允许SWIG 一个不复制的机会..?或者,也许接受 Python [string] 对象本身而不进行隐式本机转换?
你在寻找类似this的东西吗?
我认为您正在寻找更像这样的东西:***.com/a/16998687/168175
【参考方案1】:
您可能希望将文件名传递给 C 并在那里打开并搜索它。您正在读取字节,将这些字节转换为 unicode,然后转换回定时部分内的字节。您可以阅读此处的文档以了解其内部结构。
https://docs.python.org/3/c-api/unicode.html
如果文件是 utf-8,则通过删除解码将其保留为字节,或者仅传递文件名并将其加载到 C 中。
【讨论】:
谢谢,但我需要对字符串而不是文件进行操作。我将对这些字符串进行更多操作,因此每次从磁盘保存和加载都不是我的问题的好选择。我只需要将字符串的引用传递给 c++ 扩展。以上是关于如何有效地将大字符串从 Python 传递到 C++ 扩展方法?的主要内容,如果未能解决你的问题,请参考以下文章
如何有效地将大文件加载到 IndexedDB 存储中?我的应用程序在超过 100,000 行时崩溃