, Boost.Python은 TypeWrappers와 의미를 전달 파이썬 인수를 유지한다. 따라서 Python에서 노출 된 C++ 함수로 목록을 전달할 때 Python 목록을 boost::python::list
객체로 받아들임으로써 참조를 만들고 유지 관리 할 수 있습니다.
상세한 답변은 실제로 좀 더 깊이 있습니다. 그것을 탐구하기 전에 혼동을 피하기 위해 몇 가지 의미를 확장하겠습니다. 파이썬의 가비지 콜렉션과 객체 별 의미론을 통해, 일반적인 경험 법칙은 Boost.Python TypeWrappers를 스마트 포인터로 취급하는 것입니다.
- 이 함수가 목록을
boost::python::list
개체로 허용하면 C++에 이제 Python 개체에 대한 참조가 있습니다. 파이썬리스트의 수명은 최소한 booot::python::list
객체만큼 길어질 것입니다.
- 파이썬 목록이
std::vector
과 같이 다른 유형으로 변환 된 경우 C++에서 파이썬 목록에 대한 복사본을 생성했습니다. 이 사본은 원래 목록과 관련이 없습니다. #include <iostream> // std::cout
#include <utility> // std::make_pair
#include <boost/foreach.hpp>
#include <boost/python.hpp>
#include <boost/python/stl_iterator.hpp>
boost::python::list list;
/// @brief Store handle to the list.
///
/// @param pylist Python list for which a handle will be maintained.
void set(const boost::python::list& pylist)
{
// As the boost::python::list object is smart-pointer like, this
// creates a reference to the python list, rather than creating a
// copy of the python list.
list = pylist;
}
// Iterate over the current list, printing all ints.
void display()
{
std::cout << "in display" << std::endl;
typedef boost::python::stl_input_iterator<int> iterator_type;
BOOST_FOREACH(const iterator_type::value_type& data,
std::make_pair(iterator_type(list), // begin
iterator_type())) // end
{
std::cout << data << std::endl;
}
}
BOOST_PYTHON_MODULE(example) {
namespace python = boost::python;
python::def("set", &set);
python::def("display", &display);
}
그리고 그것의 사용 : : 여기
은 핸들을 유지하고, 그 내용을 인쇄, 파이썬 목록을 전달할 수있는 C의 ++ 모듈의 간단한 예입니다
>>> import example
>>>
>>> x = range(2)
>>> x
[0, 1]
>>> example.set(x)
>>> example.display()
in display
0
1
>>> x[:] = range(7, 10)
>>> example.display()
in display
7
8
9
질문에서 소개되는 복잡성 중 하나는 언제든지 에있는 C++의 Python 목록을 읽으려는 것입니다. 가장 복잡한 경우은 언제든지 C++ 스레드 내에서 발생할 수 있습니다. 언제든지이 발생할 수 있습니다.
기본적으로 시작하자. Python의 Global Interpreter Lock (GIL). 즉, GIL은 통역사 주위의 뮤텍스입니다. 쓰레드가 파이썬 관리 객체의 참조 카운팅에 영향을 미치는 것이 있다면, GIL을 획득해야합니다. 때때로 참조 횟수가 매우 투명하지, 고려 : 일정한 기준으로 list
을 받아
typedef boost::python::stl_input_iterator<int> iterator_type;
iterator_type iterator(list);
boost::python::stl_input_iterator
있지만 생성자 내에서 파이썬 목록에 대한 참조를 만듭니다.
위의 예에서 C++ 스레드가 없었기 때문에 GIL을 획득하는 동안 모든 동작이 발생했습니다.그러나 display()
이 C++ 내에서 언제든지 호출 될 수 있으면 몇 가지 설정이 필요합니다.
먼저, 모듈은 파이썬이 스레딩을 위해 GIL을 초기화해야합니다. 편의를 위해
BOOST_PYTHON_MODULE(example) {
PyEval_InitThreads(); // Initialize GIL to support non-python threads.
...
}
가 관리하는 GIL 도움이되는 간단한 클래스 만들 수 있습니다 :
/// @brief RAII class used to lock and unlock the GIL.
class gil_lock
{
public:
gil_lock() { state_ = PyGILState_Ensure(); }
~gil_lock() { PyGILState_Release(state_); }
private:
PyGILState_STATE state_;
};
는 C++ 스레드와 상호 작용을 표시하려면를, 응용 프로그램이 일정 할 수 있도록 모듈에 기능을 추가 할 수 있습니다 목록의 내용이 표시 될 때까지 지연됩니다.
#include <iostream> // std::cout
#include <utility> // std::make_pair
#include <boost/foreach.hpp>
#include <boost/python.hpp>
#include <boost/python/stl_iterator.hpp>
#include <boost/thread.hpp>
boost::python::list list;
/// @brief Store handle to the list.
///
/// @param pylist Python list for which a handle will be maintained.
void set(const boost::python::list& pylist)
{
list = pylist;
}
// Iterate over the current list, printing all ints.
void display()
{
std::cout << "in display" << std::endl;
typedef boost::python::stl_input_iterator<int> iterator_type;
BOOST_FOREACH(const iterator_type::value_type& data,
std::make_pair(iterator_type(list), // begin
iterator_type())) // end
{
std::cout << data << std::endl;
}
}
/// @brief RAII class used to lock and unlock the GIL.
class gil_lock
{
public:
gil_lock() { state_ = PyGILState_Ensure(); }
~gil_lock() { PyGILState_Release(state_); }
private:
PyGILState_STATE state_;
};
/// @brief Entry point for delayed display thread.
///
/// @param Delay in seconds.
void display_in_main(unsigned int seconds)
{
boost::this_thread::sleep_for(boost::chrono::seconds(seconds));
gil_lock lock; // Acquire GIL.
display(); // Can safely modify python objects.
// GIL released when lock goes out of scope.
}
/// @brief Schedule the list to be displayed.
///
/// @param Delay in seconds.
void display_in(unsigned int seconds)
{
// Start detached thread.
boost::thread(&display_in_main, seconds).detach();
}
BOOST_PYTHON_MODULE(example) {
PyEval_InitThreads(); // Initialize GIL to support non-python threads.
namespace python = boost::python;
python::def("set", &set);
python::def("display", &display);
python::def("display_in", &display_in);
}
그리고 그것의 사용 : : 여기
/// @brief Entry point for delayed display thread.
///
/// @param Delay in seconds.
void display_in_main(unsigned int seconds)
{
boost::this_thread::sleep_for(boost::chrono::seconds(seconds));
gil_lock lock; // Acquire GIL.
display(); // Can safely modify python objects.
// GIL released when lock goes out of scope.
}
/// @brief Schedule the list to be displayed.
///
/// @param Delay in seconds.
void display_in(unsigned int seconds)
{
// Start detached thread.
boost::thread(&display_in_main, seconds).detach();
}
은 완전한 예입니다
>>> import example
>>> from time import sleep
>>>
>>> x = range(2)
>>> example.set(x)
>>> example.display()
in display
0
1
>>> example.display_in(3)
>>> x[:] = range(7, 10)
>>> print "sleeping"
sleeping
>>> sleep(6)
in display
7
8
9
sleep(6)
전화 6 초 동안 차단 파이썬 콘솔의 C++ 스레드가 GIL를 인수하면서 목록 x
의 내용을 표시하고 GIL을 릴리스했습니다.
감사의 말씀을 전하고 싶습니다. 아마도 C++에 대한 목록 참조를 얻으려고 시도했을 때 약간의 실수를 저질렀습니다. 여기에 멀티 스레딩과 관련하여 stackoverflow에 또 다른 질문이 있습니다. 나는 잠금까지 생각하기까지는 그다지 멀지 않았다. 그래서 기본적으로 당신은 제가 기대했던 것보다 더 많은 것을 도왔습니다. (제 질문의 약 1/2) 그리고 오늘 나를 기뻤습니다. D 아주 많이 다시 한번 감사드립니다. –
@ 크리스 : 도와 줘서 기뻐요. (Boost.Python의 질문에 [tag : boost-python] 태그로 태그를 지정하면 더 많은 잠재 고객에게 다가 갈 수 있습니다. –