Pybind11 के साथ बहु-थ्रेडेड C ++ प्रोग्राम में पायथन दुभाषिया को एम्बेड करना
मैं pybind11 का उपयोग करने की कोशिश कर रहा हूं ताकि एक 3rd पार्टी C ++ लाइब्रेरी को पायथन विधि कहा जा सके। पुस्तकालय बहुआयामी है, और प्रत्येक थ्रेड एक पायथन ऑब्जेक्ट बनाता है, और फिर ऑब्जेक्ट के तरीकों के लिए कई कॉल करता है।
मेरी समस्या यह है कि py::gil_scoped_acquire acquire;
गतिरोध को बुलावा । एक न्यूनतम कोड जो समस्या को पुन: पेश करता है, नीचे दिया गया है। मैं क्या गलत कर रहा हूं?
// main.cpp
class Wrapper
{
public:
Wrapper()
{
py::gil_scoped_acquire acquire;
auto obj = py::module::import("main").attr("PythonClass")();
_get_x = obj.attr("get_x");
_set_x = obj.attr("set_x");
}
int get_x()
{
py::gil_scoped_acquire acquire;
return _get_x().cast<int>();
}
void set_x(int x)
{
py::gil_scoped_acquire acquire;
_set_x(x);
}
private:
py::object _get_x;
py::object _set_x;
};
void thread_func()
{
Wrapper w;
for (int i = 0; i < 10; i++)
{
w.set_x(i);
std::cout << "thread: " << std::this_thread::get_id() << " w.get_x(): " << w.get_x() << std::endl;
std::this_thread::sleep_for(100ms);
}
}
int main() {
py::scoped_interpreter python;
std::vector<std::thread> threads;
for (int i = 0; i < 5; ++i)
threads.push_back(std::thread(thread_func));
for (auto& t : threads)
t.join();
return 0;
}
और पायथन कोड:
// main.py
class PythonClass:
def __init__(self):
self._x = 0
def get_x(self):
return self._x
def set_x(self, x):
self._x = x
संबंधित प्रश्न यहां और यहां मिल सकते हैं , लेकिन समस्या को हल करने में मेरी मदद नहीं की।
जवाब
मैंने श्रमिक सूत्र (जोड़ा py::gil_scoped_release release;
) शुरू करने से पहले मुख्य सूत्र में जीआईएल जारी करके समस्या को हल करने में कामयाब रहा । जो कोई भी रुचि रखता है, उसके लिए अब निम्नलिखित काम करता है (पायथन ऑब्जेक्ट्स की सफाई को भी जोड़ा):
#include <pybind11/embed.h>
#include <iostream>
#include <thread>
#include <chrono>
#include <sstream>
namespace py = pybind11;
using namespace std::chrono_literals;
class Wrapper
{
public:
Wrapper()
{
py::gil_scoped_acquire acquire;
_obj = py::module::import("main").attr("PythonClass")();
_get_x = _obj.attr("get_x");
_set_x = _obj.attr("set_x");
}
~Wrapper()
{
_get_x.release();
_set_x.release();
}
int get_x()
{
py::gil_scoped_acquire acquire;
return _get_x().cast<int>();
}
void set_x(int x)
{
py::gil_scoped_acquire acquire;
_set_x(x);
}
private:
py::object _obj;
py::object _get_x;
py::object _set_x;
};
void thread_func(int iteration)
{
Wrapper w;
for (int i = 0; i < 10; i++)
{
w.set_x(i);
std::stringstream msg;
msg << "iteration: " << iteration << " thread: " << std::this_thread::get_id() << " w.get_x(): " << w.get_x() << std::endl;
std::cout << msg.str();
std::this_thread::sleep_for(100ms);
}
}
int main() {
py::scoped_interpreter python;
py::gil_scoped_release release; // add this to release the GIL
std::vector<std::thread> threads;
for (int i = 0; i < 5; ++i)
threads.push_back(std::thread(thread_func, 1));
for (auto& t : threads)
t.join();
return 0;
}
पाइथन को ग्लोबल इंटरप्रेटर लॉक कहा जाता है ।
इसलिए आपको मूल रूप से अपने खुद के पायथन इंटरप्रेटर को खरोंच से लिखना होगा, या पायथन के स्रोत कोड को डाउनलोड करना होगा और इसे बहुत सुधारना होगा।
आप लिनक्स पर हैं, तो आप (उपयुक्त का उपयोग कर कई अजगर दुभाषिए चलाने पर विचार कर सकता है syscalls (2) के साथ, पाइप (7) या यूनिक्स (7) के लिए interprocess संचार ) - शायद एक अजगर प्रक्रिया अपने सी ++ धागे में से प्रत्येक के साथ संवाद।
मैं क्या गलत कर रहा हूं?
पायथन में कोडिंग कुछ ऐसा है जिसे अन्यथा कोडित किया जाना चाहिए। क्या आपने एसबीसीएल की कोशिश करने पर विचार किया ?
कुछ पुस्तकालयों (जैसे टेन्सरफ़्लो ) को पायथन और सी ++ दोनों से बुलाया जा सकता है। शायद आप उनसे प्रेरणा ले सकें ...
व्यवहार में, यदि आपके पास एक शक्तिशाली लिनक्स मशीन पर सिर्फ एक दर्जन सी ++ धागे हैं, तो आप प्रति पायल धागे में एक पायथन प्रक्रिया कर सकते हैं । इसलिए प्रत्येक C ++ धागे की अपनी साथी पायथन प्रक्रिया होगी।
अन्यथा, अपनी जीआईएल को हटाने के लिए पायथन के स्रोत कोड को सुधारने के लिए कई वर्षों के काम का बजट। आप उस कार्य पर मदद करने के लिए अपने GCC प्लगइन को कोड कर सकते हैं-Pyaly के C कोड को समझने और समझने में आपकी मदद करेंगे