#python #c #multithreading #pybind11 #python-bindings
Вопрос:
Я просто печатаю значение car1.vehicle_id в python. Я хочу, чтобы он печатал «1234» в течение первых 2 секунд, а затем, когда значение изменится в другом потоке на «4543» , изменение должно вступить в силу в python. Возможно ли это или есть простой пример, который поможет мне в этом?
c
#include lt;pybind11/embed.hgt; #include lt;stringgt; #include lt;threadgt; #include lt;chronogt; // Define namespace for pybind11 namespace py = pybind11; class Vehiclee { // Access specifier public: Vehiclee(){}; ~Vehiclee() {} // Data Members int vehicle_id; std::string vehicle_name; std::string vehicle_color; // Member Functions() void printname() { std::cout lt;lt; "Vehicle id is: " lt;lt; vehicle_id; std::cout lt;lt; "Vehicle name is: " lt;lt; vehicle_name; std::cout lt;lt; "Vehicle color is: " lt;lt; vehicle_color; } }; PYBIND11_EMBEDDED_MODULE(embeded, m){ py::class_(m, "Vehiclee") .def_readonly("vehicle_name", amp;Vehiclee::vehicle_name) .def_readonly("vehicle_color", amp;Vehiclee::vehicle_color) .def_readonly("vehicle_id", amp;Vehiclee::vehicle_id); } py::scoped_interpreter python{}; Vehiclee car1; void threadFunc() { sleep(2); std::coutlt;lt;"entering thread"; car1.vehicle_id = 4543; std::coutlt;lt;"Modified val in thread"; } int main() { // Initialize the python interpreter // Import all the functions from scripts by file name in the working directory auto simpleFuncs = py::module::import("simpleFuncs"); // Test if C objects can be passed into python functions car1.vehicle_id = 1234; std::thread t1(threadFunc); simpleFuncs.attr("simplePrint")(car1); t1.join(); return 0; }
питон
gt; import time gt; import importlib gt; import embeded gt; gt; def simplePrint(argument): gt; while(1): gt; importlib.reload(embeded) gt; print(argument.vehicle_id) time.sleep(1)
Выходной ток
всегда 1234
Требуемая производительность
1234 (for first 2 secs) 4543 (after 2 secs)
Ответ №1:
Вам нужно понять правила C для потоковой передачи. В C потоки могут работать намного лучше параллельно, чем в Python. Это связано с тем, что в C потоки по умолчанию выполняются полностью отдельно друг от друга, в то время как Python использует глобальную блокировку интерпретатора, которая вызывает большую синхронизацию потоков.
Итак, в этом случае вам действительно нужна синхронизация потоков, потому что потоки совместно используют переменную ( car1
). Проблема в том, что .def_readonly
скрывается некоторый шаблонный код, который не выполняет синхронизацию — имеет смысл, потому что какой объект он должен использовать для синхронизации?
Итак , что вам нужно сделать, это ввести методы получения и установки Vehicle
и добавить a std::mutex
. В каждом геттере и каждом сеттере вы блокируете и разблокируете этот мьютекс. Это легко сделать с помощью a std::scoped_lock
— это автоматически разблокирует мьютекс, когда метод вернется.
Есть и другие варианты. Ибо vehicle_id
вы могли бы использовать a std::atomic_int
, но вам, вероятно, все равно понадобится метод получения. Я не думаю, что pybind понимает атомарные переменные.