Используйте python obj в c ++ с pybind и multiprocessing.Process - PullRequest
1 голос
/ 21 февраля 2020

Я пытаюсь реализовать C ++ в python с использованием pybind11 и использую pybind11-multiprocessing-hangs . Разница в том, что я хочу использовать объект python в c ++ и продолжать вызывать методы класса из c ++. Вот код:

#ifdef _WIN32
#include "direct.h"
#define PATH_SEP '\\'
#define GETCWD _getcwd
#define CHDIR _chdir
#else
#include "unistd.h"
#define PATH_SEP '/'
#define GETCWD getcwd
#define CHDIR chdir
#endif
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/stl_bind.h>
#include <pybind11/embed.h>
#include <iostream>

namespace py = pybind11;
using namespace py::literals;
bool ChangeDirectory(const char* dir) { return CHDIR(dir) == 0; }
int wmain(int argc, wchar_t** argv)
{
    py::initialize_interpreter();
    PySys_SetArgv(argc, argv);

    std::string pyCode = std::string(R"(
import os
import sys
from queue import Empty, Full
from multiprocessing import Queue as mQueue, Process as mProcess
import sys
sys.executable = "C:\\Users\\nb\\scoop\\apps\\python\\current\\python.exe"
__file__ = "D:\\sw\\run.py"
print("Hello stackoverflow!", file=open("output.txt", "a"))
class C2PyMulti(object):
    """docstring for TactileEngine"""
    def __init__(self):
        self.te_ops = MultiProcessTest()

    def compose(self,data): 
        self.te_ops.load_q(data)

class MultiProcessTest(object):
    def __init__(self):
        self.my_q = mQueue()
        self.spawn_processes()

    def load_q(self, data):
        self.my_q.put(('print',data))

    def spawn_processes(self):
        args = (self.my_q,'inside message_coordinator')
        self.message_coordinator = mProcess(target=message_coordinator, args=args)
        try:
            # Starts the data processor
            val = self.message_coordinator.start()
            if val == 1:
                self.message_coordinator.join()
        except Exception:
            print('failed spawn!')


def message_coordinator(mQ,num):    
    print(num)
    while True:
        try:
            command, args= mQ.get(timeout=.0001)
            if  command == 'print':
                print(args, file=open("output.txt", "a"))  
            elif command == 'end':
                return 1
        except (Empty):
            pass


cpy2 = C2PyMulti()
cpy2.compose('hello')
cpy2.compose('hello')
cpy2.compose('hello')
cpy2.compose('hello')
cpy2.compose('end')
del cpy2
    )");
    try
    {
        FILE* f = nullptr;
        fopen_s(&f, "D:\\sw\\run.py", "wt");
        fprintf(f, "%s", pyCode.c_str());
        fclose(f);
        ChangeDirectory("D:\sw\run.py");
        //py::module C2py = py::module::import("run"); ///does not work can't find the module
        //py::object C2PyMulti = C2py.attr("C2PyMulti");
        //py::object c2py = C2PyMulti();
        //c2py.attr("load_q")("hello");
        py::exec(pyCode);
    }
    catch (const std::exception & e) {
        std::cout << e.what();
    }
    py::finalize_interpreter();
}

, а вот вывод output.txt:

Hello stackoverflow!
Hello stackoverflow!
Hello stackoverflow!
Hello stackoverflow!
Hello stackoverflow!
Hello stackoverflow!
Hello stackoverflow!
Hello stackoverflow!
Hello stackoverflow!

В конечном счете, я хочу использовать нечто похожее на приведенное ниже:

py::module C2py = py::module::import("C2PyMulti");
py::object C2PyMulti = C2py.attr("C2PyMulti");
py::object c2py = C2PyMulti();
c2py.attr("load_q")("hello");

Мои извинения раньше времени.

1 Ответ

0 голосов
/ 21 февраля 2020

Итак, чтобы ответить на вопрос, мне нужно было разделить метод message_coordinator и вызвать его через другой поток, например:

void message(py::module C2py, py::object queue) {
    py::object message_coordinator = C2py.attr("message_coordinator")(queue, "In Message Coordinator!");
}

, и вызвать его через std::thread ti(message, C2py, q);, поэтому конечный результат:

#ifdef _WIN32
#include "direct.h"
#define PATH_SEP '\\'
#define GETCWD _getcwd
#define CHDIR _chdir
#else
#include "unistd.h"
#define PATH_SEP '/'
#define GETCWD getcwd
#define CHDIR chdir
#endif
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/stl_bind.h>
#include <pybind11/embed.h>
#include <iostream>
#include <thread>

namespace py = pybind11;
using namespace py::literals;
bool ChangeDirectory(const char* dir) { return CHDIR(dir) == 0; }

void message(py::module C2py, py::object queue) {
    py::object message_coordinator = C2py.attr("message_coordinator")(queue, "In Message Coordinator!");
}

int wmain(int argc, wchar_t** argv)
{
    py::initialize_interpreter();
    PySys_SetArgv(argc, argv);

    std::string pyCode = std::string(R"(
import os
import sys
from queue import Empty, Full
from multiprocessing import Queue as mQueue, Process as mProcess
import sys
sys.executable = "C:\\Users\\nb\\scoop\\apps\\python\\current\\python.exe"
__file__ = "D:\\sw\\run.py"
print("Start of module!")
class C2PyMulti(object):
    """docstring for TactileEngine"""
    def __init__(self):
        pass

    def build(self):
        return MultiProcessTest()

    def compose(self,te_ops, data): 
        te_ops.load_q(data)

class MultiProcessTest(object):
    def __init__(self):

        print("Start of MultiProcessTest!")
        #self.spawn_processes()

    def build_q(self):    
        self.my_q = mQueue()
        return self.my_q

    def load_q(self, data):
        self.my_q.put(('print',data))

    def spawn_processes(self):
        args = (self.my_q,'Inside message_coordinator')
        self.message_coordinator = mProcess(target=message_coordinator, args=args)
        try:
            # Starts the data processor
            self.message_coordinator.start()
        except Exception:
            print('failed spawn!')


def message_coordinator(mQ,num):    
    print(num)
    while True:
        try:
            command, args= mQ.get(timeout=.0001)
            if  command == 'print':
                print("command: {}, args: {}".format(command,args))  
            elif command == 'end':
                print("command: {}, args: {}".format(command,args))  
        except (Empty):
            pass

    )");
    try
    {
        FILE* f = nullptr;
        fopen_s(&f, "D:\\sw\\run.py", "wt");
        fprintf(f, "%s", pyCode.c_str());
        fclose(f);
        ChangeDirectory("D:/sw");
        py::module C2py = py::module::import("run");
        py::object C2PyMulti = C2py.attr("C2PyMulti");
        py::object c2py = C2PyMulti();
        py::object c2pybuild = c2py.attr("build");
        py::object b = c2pybuild();
        py::object q = b.attr("build_q")();
        py::object compose = c2py.attr("compose");
        compose(b, "fromoutside");
        compose(b, "fromoutside2");
        compose(b, "fromoutside3");
        compose(b, "fromoutside4");
        compose(b, "fromoutside5");
        compose(b, "fromoutside6");
        compose(b, "fromoutside7");
        compose(b, "fromoutside8");


        std::thread ti(message, C2py, q);
        compose(b, "fromoutside9");
        compose(b, "fromoutside10");
        b.attr("load_q")("hello4");
        b.attr("load_q")("hello5");
        b.attr("load_q")("hello6");

        while (true)
        {
            std::this_thread::sleep_for(std::chrono::seconds(1));
        }
        //py::exec(pyCode);
    }
    catch (const std::exception & e) {
        std::cout << e.what();
    }
    py::finalize_interpreter();
}
...