boost.python不支持并行?
我正在尝试使用 boost.python 将一段 C++ 代码包装到 python lib 中,但是,我发现多个实例无法同时运行:
code (C++):
class Foo{
public:
Foo(){}
void run(){
int seconds = 2;
clock_t endwait;
endwait = clock () + seconds * CLOCKS_PER_SEC ;
while (clock() < endwait) {}
}
};
BOOST_PYTHON_MODULE(run_test)
{
using namespace boost::python;
class_<Foo>("test", init<>())
.def("run", &Foo::run)
;
}
which is compile using CMake (CMake):
add_library(run_test SHARED run_test.cpp)
target_link_libraries(run_test boost_python python2.7)
and tested以下代码(Python):
class Dos(threading.Thread):
def run(self):
printl('performing DoS attack')
proc = test()
proc.run()
for i in range(5):
t = Dos()
t.start()
输出表明代码以一种非常奇怪的方式并行化。每个线程只需要 2 秒,并且在我的四核机器上应该同时运行 4 个线程:
[2011-11-04 13:57:01] performing DoS attack
[2011-11-04 13:57:01] performing DoS attack
[2011-11-04 13:57:05] performing DoS attack
[2011-11-04 13:57:05] performing DoS attack
[2011-11-04 13:57:09] performing DoS attack
感谢您的帮助!
I am trying to wrap a piece of C++ code into python lib using boost.python, however, I found out that multiple instances cannot run at the same time:
code (C++):
class Foo{
public:
Foo(){}
void run(){
int seconds = 2;
clock_t endwait;
endwait = clock () + seconds * CLOCKS_PER_SEC ;
while (clock() < endwait) {}
}
};
BOOST_PYTHON_MODULE(run_test)
{
using namespace boost::python;
class_<Foo>("test", init<>())
.def("run", &Foo::run)
;
}
which is compile using CMake (CMake):
add_library(run_test SHARED run_test.cpp)
target_link_libraries(run_test boost_python python2.7)
and tested with the following code (Python):
class Dos(threading.Thread):
def run(self):
printl('performing DoS attack')
proc = test()
proc.run()
for i in range(5):
t = Dos()
t.start()
The output indicates that the code is parallelized in a very weird way. Each thread should take only 2 seconds and 4 threads should run simultaneously on my quadcore machine:
[2011-11-04 13:57:01] performing DoS attack
[2011-11-04 13:57:01] performing DoS attack
[2011-11-04 13:57:05] performing DoS attack
[2011-11-04 13:57:05] performing DoS attack
[2011-11-04 13:57:09] performing DoS attack
thank you for your help!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您遇到的是 python 全局解释器锁。 GIL 一次只允许一个线程在 python 解释器中运行。
Boost.Python 的优点之一是您可以释放 GIL,执行 C++ 操作,然后在完成后将其收回。然而这也是一种责任。 Python 通常会定期释放 GIL,以便为其他线程提供运行的机会。如果您使用 C++,这就是您的工作。如果你拿着 GIL 花 2 个小时来处理数字,你将会冻结整个解释器。
通过一点反向 RAII 可以很容易地解决这个问题:
现在您可以像这样更改代码:
非常重要的是要注意,在不持有 GIL 的情况下,您不得触摸任何 python 代码、python 数据或调用解释器。这将导致你的解释器崩溃。
也可以走另一条路。当前未持有 GIL 的线程可以获取它,并调用 python。这可以是一个较早释放 GIL 的线程,也可以是一个在 C++ 中启动但从未拥有过 GIL 的线程。这是 RAII 类:
用法留给学生作为练习。
附加说明(我总是忘记提及这一点):
如果你打算在 C++ 中搞乱 GIL,你的模块定义需要从以下代码开始:
What you are running into is the python Global Interpreter Lock. The GIL only allows one thread at a time to run in the python interpreter.
One of the advantages of Boost.Python is that you can release the GIL, do C++ stuff, and then take it back when you are done. This is also a responsibility however. Python normally releases the GIL at regular intervals, to give other threads a chance to run. If you are in C++, this is your job. If you go crunch numbers for 2 hours while holding the GIL, you will freeze the whole interpreter.
This can be easy to fix with a little reverse RAII:
Now you can change your code like so:
It is VERY important to note that you MUST NOT touch any python code, or python data or call in to the interpreter while not holding the GIL. This will cause your interpreter to crash.
It is also possible to go the other way. A thread not currently holding the GIL can acquire it, and make calls in to python. This can be a thread that released the GIL earlier, or one that started in c++ and never had the GIL. Here is the RAII class for that:
Usage is left as an exercise for the student.
Additional note (I always forget to mention this):
If you are going to be messing with the GIL in c++ your module definition needs to start with this code: