我对使用boost.python库构建的python扩展的行为非常奇怪。即,在一段代码中:
import my_ext
j = 0
while j<5:
print j
my_ext.do_something(j)
j = j + 1
我没有看到j被打印出来,而扩展代码(my_ext.do_something(j)
)正在为不同的j做一些工作(比如打印第j个文件)。此外,它只打印2个文件,j = 0和j = 1,然后整个脚本完成没有错误或其他通知。
所有这些让我觉得代码是并行执行的(多线程),但没有正确处理这样的并行化。我想这可能与我建立的boost.python库默认使用--threading = multi选项有关。但是,尝试使用选项--threading = single进行重建不会产生任何影响,它仍然构建为多线程库。这篇文章http://mail.python.org/pipermail/cplusplus-sig/2010-October/015771.html报告了类似的构建过程问题,但是没有答案。
所以我的问题是如何构建boost库和boost.python特别是单线程。或者,问题可能与boost.python库的单/多线程之外的其他问题有关。
附加信息:我正在使用cygwin,boost_1.50.0,python2.6,我的操作系统是带有多核CPU和nvidia vram的Win 7(后者的harware可能都支持多线程执行我的扩展而不让我知道)。
答案 0 :(得分:1)
Boost.Python往往是Boost构建系统中的一个特例,因为它与已构建Python的Python版本和配置相关联。例如,如果Python是在没有调试的情况下构建的,那么Boost.Python将在没有调试的情况下构建,即使明确告知Boost构建调试变体。我相信线程属性也是如此,因为它会通过包含pyconfig.h
来间接包含Python.h
。
Python默认在单个线程中运行程序,无论Python是否使用线程支持构建。 Boost.Python不会改变这种行为。作为一般的经验法则,当需要并发时,线程只会成为Boost.Python的一个因素。例如,如果my_ext.do_something()
要将大文件读入内存,那么在不保留lock on the interpreter的情况下执行读取可能是最佳的。
考虑从扩展的简化实现开始,然后扩展它。例如,当我将my_ext
构建为:
#include <iostream>
#include <boost/python.hpp>
void do_something(unsigned int j)
{
std::cout << "do_something(): " << j << std::endl;
}
BOOST_PYTHON_MODULE(my_ext)
{
namespace python = boost::python;
python::def("do_something", &do_something);
}
我的测试脚本:
import my_ext
for j in xrange(5):
print j
my_ext.do_something(j)
产生
0 do_something(): 0 1 do_something(): 1 2 do_something(): 2 3 do_something(): 3 4 do_something(): 4
另一种方法是构建Python和Boost.Python的调试版本,然后使用调试器逐步执行该程序。有关调试版本的更多信息可以在here找到。