6
C++関数ポインタを使用して関数呼び出しのシーケンスを格納する拡張モジュールを作成しました。私は別のプロセスでこれらの呼び出しシーケンスをPythonのmultiprocessing
モジュールを使って実行したい(共有状態はないので同期の問題はない)。関数ポインタはプロセス間で有効なままですか?
multiprocessing
の後に機能ポインタ(データポインタではない)が有効であるかどうかを知る必要があります。fork()
です。
C++モジュール:でコンパイル
#include <list>
#include <boost/assert.hpp>
#include <boost/python.hpp>
#include <boost/python/stl_iterator.hpp>
#include <boost/foreach.hpp>
/*
* Some functions to be called
*/
double funcA(double d) { return d; }
double funcB(double d) { return d + 3.14; }
double funcC(double d) { return d - 42.0; }
/*
* My container of function pointers (picklable to allow use with multiprocessing)
*/
typedef double(*func_ptr_t)(double);
struct CallSequence {
CallSequence() {
_seq.push_back(funcA);
_seq.push_back(funcB);
_seq.push_back(funcC);
}
std::list<func_ptr_t> _seq;
};
template <typename cast_type>
struct CallSequence_picklesuite : boost::python::pickle_suite {
BOOST_STATIC_ASSERT_MSG(sizeof(cast_type) == sizeof(func_ptr_t), CANNOT_CAST_POINTER_TO_REQUESTED_TYPE);
static boost::python::list getstate(const CallSequence& cs) {
boost::python::list ret;
BOOST_FOREACH(func_ptr_t p, cs._seq)
ret.append(reinterpret_cast<cast_type>(p));
return ret;
}
static void setstate(CallSequence& cs, boost::python::list l) {
std::list<func_ptr_t> new_list;
boost::python::stl_input_iterator<cast_type> begin(l), end;
for(; begin != end; begin++)
new_list.push_back(reinterpret_cast<func_ptr_t>(*begin));
cs._seq.swap(new_list);
}
};
/*
* Run the call sequence
*/
double runner(const CallSequence& cs) {
double ret = 0;
BOOST_FOREACH(const func_ptr_t& p, cs._seq)
ret += p(2.18);
return ret;
}
BOOST_PYTHON_MODULE(my_extension) {
using namespace ::boost::python;
class_<CallSequence>("CallSequence")
.def_pickle(CallSequence_picklesuite<unsigned int>());
def("runner", runner);
}
:
$ g++ question1.cpp -lboost_python -I /usr/include/python2.7 -shared -o my_extension.so
Pythonコード複数のプロセス間でそれを呼び出す:
#!/usr/bin/python
from multiprocessing import Pool
import my_extension
def runner(sequence):
return my_extension.runner(sequence)
def main():
l = [my_extension.CallSequence() for _ in range(200)]
pool = Pool(processes=4)
print pool.map(runner, l)
if __name__ == '__main__':
main()
期待どおりに出力されます。私はちょうど '幸運を得ている'か、またはfork()
の後に関数ポインタが有効なままであることを確実に期待できるかどうかを知りたい。
私の(今削除された)回答に対するあなたのコメントは、 'fork'がアドレス空間をコピーするのを知らなかったからです。私の答えは2つの完全に無関係のプロセスに対して正しいはずでした。私は「fork」とは思っていましたが、もちろん私は間違っていました。 +1 –
Windowsではフォークしませんが、新しいPythonインタプリタを実行します。私はこれもOPのコードでうまくいくと思います。こちらをご覧ください:http://bugs.python.org/issue8713 –