虽然这个问题有几个答案,但没有一个对我有用。
我有一个 cython 项目,其中包含一个执行多线程的类。
cythonMod.pyx:
class doThreadingStuff(Process):
KillIt = False
def __init__(self, to_emitter: Pipe, queue_from_mother: Queue, queue_to_mother: Queue, daemon=True):
super().__init__()
def run(self):
threading.Thread(target=wasupbrah, daemon=True, name="wasupbrah",
args=(self.queue_to_mother,self.queue_from_mother, text,)).start()
def wasupbrah(queue_to_mother, queue_from_mother):
print("[+] called wasupbrah")
# do stuff
cdef public void mainCode():
print("Running MainCode() here")
if ctypes.windll.shell32.IsUserAnAdmin():
#do PyQt Stuff
app = QtWidgets.QApplication(sys.argv)
mother_pipe, child_pipe = Pipe()
queue_to_mother = Queue()
queue_from_mother = Queue()
emitter = QtDesignerStuff.Emitter(mother_pipe, queue_to_mother, queue_from_mother)
dThS = doThreadingStuff(child_pipe, queue_from_mother, queue_to_mother)
dThS.start()
不幸的是,我无法提供完整的代码,但我提供了我认为有问题的部分。
如果您使用 cython 在上面进行编译,它将生成一个
cythonMod.pyd
、cythonMod.c
和 cythonMod.h
,以及使 mainCode
函数成为公共声明,可供外部 C 代码访问。
如果我移动
mainCode
说 runcythonMod.py
并以 python runcythonMod.py
运行它,它会完美运行。
现在,我有一个 C 程序,它简单地调用 cython 项目中的
mainCode
函数,如下所示:
runcythonMod.c:
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <stdio.h>
#include "runcythonMod.h"
#include "nanalyzer.h"
//compile using: gcc -o runcythonMod.exe cythonMod.c cythonMod.c -IC:\Users\username\AppData\Local\Programs\Python\Python39\include -IC:\Users\username\AppData\Local\Programs\Python\Python39\include -LC:\Users\username\AppData\Local\Programs\Python\Python39\libs -lpython39
int main(){
printf("current PID %d\n", getpid());
PyImport_AppendInittab("mainCode", PyInit_cythonMod);
Py_Initialize();
//PySys_SetPath("C:/Users/username/AppData/Local/Programs/Python/python39/;.");
PyObject *sys = PyImport_ImportModule("sys");
PyObject *path = PyObject_GetAttrString(sys, "path");
PyList_Append(path, PyUnicode_FromString("."));
PyList_Append(path, PyUnicode_FromString("C:/Users/username/AppData/Local/Programs/Python/python39/"));
/* 1st: Import the module */
PyObject* ModuleString = PyUnicode_FromString((char*) "commonmodules");
if (!ModuleString) {
PyErr_Print();
printf("Error formating python script\n");
}
PyObject* Module = PyImport_Import(ModuleString);
if (!Module) {
PyErr_Print();
printf("Error importing python script\n");
}
/* 2nd: Getting reference to the function */
PyObject* Function = PyObject_GetAttrString(Module, (char*)"mainCode");
if (!Function) {
PyErr_Print();
printf("Pass valid argument to mainCode()\n");
}
printf("Good So far!\n");
if(PyImport_ImportModule("mainCode") == NULL){
printf("Failed to import mainCode\n");
}
__pyx_f_13cythonMod_mainCode();
return 0;
}
问题我认为泡菜抱怨
doThreadingStuff
是从mainCode
函数调用的,而不是从我的C的main
函数调用的。不幸的是,很难从我的 C 代码中调用 doThreadingStuff
,因为我的 cython 有一个 PyQt5 进程并在 PyQt5 应用程序和 doThreadingStuff
之间共享管道和队列。
我尝试按照网络的建议创建一个单独的函数来调用
doThreadingStuff
,但这也没有用。
File "C:\Users\username\AppData\Local\Programs\Python\Python39\Lib\multiprocessing\process.py", line 121, in start
self._popen = self._Popen(self)
File "C:\Users\username\AppData\Local\Programs\Python\Python39\Lib\multiprocessing\context.py", line 224, in _Popen
return _default_context.get_context().Process._Popen(process_obj)
File "C:\Users\username\AppData\Local\Programs\Python\Python39\Lib\multiprocessing\context.py", line 327, in _Popen
return Popen(process_obj)
File "C:\Users\username\AppData\Local\Programs\Python\Python39\Lib\multiprocessing\popen_spawn_win32.py", line 93, in __init__
reduction.dump(process_obj, to_child)
File "C:\Users\username\AppData\Local\Programs\Python\Python39\Lib\multiprocessing\reduction.py", line 60, in dump
ForkingPickler(file, protocol).dump(obj)
_pickle.PicklingError: Can't pickle <class 'cythonMod.doThreadingStuff'>: it's not the same object as cythonMod.doThreadingStuff
def pickledoThreadingStuff(child_pipe, queue_from_mother, queue_to_mother):
dThS = doThreadingStuff(child_pipe, queue_from_mother, queue_to_mother)
dThS.start()
cdef public void mainCode():
print("Running MainCode() here")
if ctypes.windll.shell32.IsUserAnAdmin():
#do PyQt Stuff
app = QtWidgets.QApplication(sys.argv)
mother_pipe, child_pipe = Pipe()
queue_to_mother = Queue()
queue_from_mother = Queue()
emitter = QtDesignerStuff.Emitter(mother_pipe, queue_to_mother, queue_from_mother)
pickledoThreadingStuff(child_pipe, queue_from_mother, queue_to_mother)
以上也没有用。
非常感谢所有回复。