Python 在decorator中运行多处理

Python 在decorator中运行多处理,python,multiprocessing,decorator,pickle,Python,Multiprocessing,Decorator,Pickle,我想重申关于多处理内部装饰器的问题(我以前的问题似乎已经过时了:)。我偶然发现了这个问题,不幸的是我不知道如何解决这个问题。为了我的应用程序的需要,我必须在装饰器内部使用多处理,但是。。。当我在decorator内部使用多处理时,我得到一个错误: 无法pickle:找不到它作为uuu main\uuuu.run\u testcase。 另一方面,当我调用我的多处理函数,比如普通函数wrapper(function,*arg)时,它就工作了。这很棘手,但我不知道我做错了什么。我几乎可以断定这是py

我想重申关于多处理内部装饰器的问题(我以前的问题似乎已经过时了:)。我偶然发现了这个问题,不幸的是我不知道如何解决这个问题。为了我的应用程序的需要,我必须在装饰器内部使用多处理,但是。。。当我在decorator内部使用多处理时,我得到一个错误:
无法pickle:找不到它作为uuu main\uuuu.run\u testcase
。 另一方面,当我调用我的多处理函数,比如普通函数
wrapper(function,*arg)
时,它就工作了。这很棘手,但我不知道我做错了什么。我几乎可以断定这是python错误:)。也许有人知道这个问题的解决方法,只保留相同的语法。我在Windows上运行此代码(不幸的是)

上一个问题:

模拟此错误的最简单代码:

来自多处理导入进程的
,事件
类ExtProcess(进程):
定义初始化(自我、事件、*args、**kwargs):
self.event=event
进程。初始化(self,*args,**kwargs)
def运行(自):
进程运行(self)
self.event.set()
类PythonHelper(对象):
@静力学方法
def并行运行(*函数):
event=event()
进程=dict()
对于函数中的函数:
fname=函数[0]
try:fargs=函数[1]
除外:fargs=list()
try:fproc=函数[2]
除外:fproc=1
对于范围内的i(fproc):
process=ExtProcess(事件,目标=fname,args=fargs)
process.start()
进程[process.pid]=进程
event.wait()
对于进程中的进程。值():
process.terminate()
对于进程中的进程。值():
process.join()
类记录器(对象):
def捕获(自我):
为True时:打印(“录制”)
从z_助手导入PythonHelper
从z_记录器导入记录器
def包装(fname,*args):
尝试:
PythonHelper.run_并行([fname,args],[Recorder().capture])
打印(“成功”)
例外情况除外,如e:
打印(“失败:{}”。格式(e))
从z_包装器导入包装器
从functools导入包装
类报告(对象):
@静力学方法
def调试(fname):
@包装(fname)
def函数(*args):
包装器(fname,args)
返回函数
执行:

来自z_报告导入报告
导入时间
类别测试(对象):
@Report.debug
def打印_x(自身,x):
对于索引,枚举中的数据(范围(x)):
打印(索引、数据);时间。睡眠(1)
如果名称=“\uuuuu main\uuuuuuuu”:
Test().print_x(10)
我在以前的版本中添加了@wrapps

我的回溯:

Traceback (most recent call last):
  File "C:\Interpreters\Python32\lib\pickle.py", line 679, in save_global
    klass = getattr(mod, name)
AttributeError: 'module' object has no attribute 'run_testcase'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\EskyTests\w_Logger.py", line 19, in <module>
    logger.run_logger()
  File "C:\EskyTests\w_Logger.py", line 14, in run_logger
    self.run_testcase()
  File "C:\EskyTests\w_Decorators.py", line 14, in wrapper
    PythonHelper.run_in_parallel([function,args],[recorder.capture])
  File "C:\EskyTests\w_PythonHelper.py", line 25, in run_in_parallel
    process.start()
  File "C:\Interpreters\Python32\lib\multiprocessing\process.py", line 130, in start
    self._popen = Popen(self)
  File "C:\Interpreters\Python32\lib\multiprocessing\forking.py", line 267, in __init__
    dump(process_obj, to_child, HIGHEST_PROTOCOL)
  File "C:\Interpreters\Python32\lib\multiprocessing\forking.py", line 190, in dump
    ForkingPickler(file, protocol).dump(obj)
  File "C:\Interpreters\Python32\lib\pickle.py", line 237, in dump
    self.save(obj)
  File "C:\Interpreters\Python32\lib\pickle.py", line 344, in save
    self.save_reduce(obj=obj, *rv)
  File "C:\Interpreters\Python32\lib\pickle.py", line 432, in save_reduce
    save(state)
  File "C:\Interpreters\Python32\lib\pickle.py", line 299, in save
    f(self, obj) # Call unbound method with explicit self
  File "C:\Interpreters\Python32\lib\pickle.py", line 623, in save_dict
    self._batch_setitems(obj.items())
  File "C:\Interpreters\Python32\lib\pickle.py", line 656, in _batch_setitems
    save(v)
  File "C:\Interpreters\Python32\lib\pickle.py", line 299, in save
    f(self, obj) # Call unbound method with explicit self
  File "C:\Interpreters\Python32\lib\pickle.py", line 683, in save_global
    (obj, module, name))
_pickle.PicklingError: Can't pickle <function run_testcase at 0x00000000027725C8>: it's not found as __main__.run_testcase
回溯(最近一次呼叫最后一次):
文件“C:\explorers\Python32\lib\pickle.py”,第679行,保存在全局
klass=getattr(mod,name)
AttributeError:“module”对象没有属性“run\u testcase”
在处理上述异常期间,发生了另一个异常:
回溯(最近一次呼叫最后一次):
文件“C:\EskyTests\w_Logger.py”,第19行,在
logger.run_logger()
文件“C:\EskyTests\w_Logger.py”,第14行,在运行日志中
self.run_testcase()
文件“C:\EskyTests\w_Decorators.py”,第14行,在包装器中
PythonHelper.run_并行([function,args],[recorder.capture])
文件“C:\EskyTests\w_PythonHelper.py”,第25行,并行运行
process.start()
文件“C:\explorers\Python32\lib\multiprocessing\process.py”,第130行,在开始处
self.\u popen=popen(self)
文件“C:\explorers\Python32\lib\multiprocessing\forking.py”,第267行,在\uuu init中__
转储(进程对象、到子进程、最高\u协议)
文件“C:\explorers\Python32\lib\multiprocessing\forking.py”,第190行,在转储中
ForkingPickler(文件、协议).dump(obj)
文件“C:\explorers\Python32\lib\pickle.py”,第237行,在转储中
自我保存(obj)
保存中第344行的文件“C:\explorers\Python32\lib\pickle.py”
自我保存(obj=obj,*rv)
文件“C:\explorers\Python32\lib\pickle.py”,第432行,在save\u reduce中
保存(状态)
保存中第299行的文件“C:\explorers\Python32\lib\pickle.py”
f(self,obj)#用显式self调用未绑定方法
保存目录中第623行的文件“C:\explorers\Python32\lib\pickle.py”
self.\u batch\u setitems(obj.items())
文件“C:\explorers\Python32\lib\pickle.py”,第656行,在批处理集合项中
保存(v)
保存中第299行的文件“C:\explorers\Python32\lib\pickle.py”
f(self,obj)#用显式self调用未绑定方法
文件“C:\explorers\Python32\lib\pickle.py”,第683行,保存在全局
(对象、模块、名称))
_pickle.PicklingError:无法pickle:找不到它作为\uuuu main\uuuu.run\u测试用例

多处理模块通过调用从进程中的pickler来“调用”这些函数。这是因为它必须通过创建的IPC接口将函数名发送给从属进程。pickler找出要使用的正确名称并将其发送出去,然后在另一端,unpickler将名称转换回函数

如果函数是类成员,则在没有帮助的情况下无法正确地对其进行pickle。对于
@staticmethod
成员来说,情况更糟,因为他们使用的是type
函数,而不是type
instancemethod
,这愚弄了pickler。无需使用
多处理
,您就可以很容易地看到这一点:

import pickle

class Klass(object):
    @staticmethod
    def func():
        print 'func()'
    def __init__(self):
        print 'Klass()'

obj = Klass()
obj.func()
print pickle.dumps(obj.func)
产生:

Klass()
func()
Traceback (most recent call last):
 ...
pickle.PicklingError: Can't pickle <function func at 0x8017e17d0>: it's not found as __main__.func
然而,一切都没有失去。您只需要添加一个间接级别。您可以提供一个在目标进程中创建实例绑定的普通函数,并至少向其发送两个参数:(pickle-able)类实例和函数名。为了完整性,我还添加了调用函数时要使用的任何参数。然后在目标进程中调用此普通函数,它将调用类的成员函数:

def call_name(instance, name, *args = (), **kwargs = None):
    "helper function for multiprocessing: call instance.getattr(name)"
    if kwargs is None:
        kwargs = {}
    getattr(instance, name)(*args, **kwargs)
现在取而代之的是
def call_name(instance, name, *args = (), **kwargs = None):
    "helper function for multiprocessing: call instance.getattr(name)"
    if kwargs is None:
        kwargs = {}
    getattr(instance, name)(*args, **kwargs)
PythonHelper.run_in_parallel([self.run_testcase],[recorder.capture])
PythonHelper.run_in_parallel([call_name, (self, 'run_testcase')],
    [recorder.capture])
Process ExtProcess-1:
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/multiprocessing/process.py", line 258, in _bootstrap
    self.run()
  File "/tmp/t/marcin/z_helper.py", line 9, in run
    Process.run(self)
  File "/usr/local/lib/python2.7/multiprocessing/process.py", line 114, in run
recording
[infinite spew of "recording" messages]
diff --git a/z_recorder.py b/z_recorder.py
index 6163a87..a482268 100644
--- a/z_recorder.py
+++ b/z_recorder.py
@@ -1,4 +1,6 @@
+import time
 class Recorder(object):
     def capture(self):
-        while True:print("recording")
-
+        while True:
+            print("recording")
+            time.sleep(5)
TypeError: print_x() takes exactly 2 arguments (1 given)
diff --git a/z_wrapper.py b/z_wrapper.py
index a0c32bf..abb1299 100644
--- a/z_wrapper.py
+++ b/z_wrapper.py
@@ -1,7 +1,7 @@
 from z_helper import PythonHelper
 from z_recorder import Recorder

-def wrapper(fname,*args):
+def wrapper(fname,args):
     try:
         PythonHelper.run_in_parallel([fname,args],[Recorder().capture])
         print("success")
    def function(*args):