python - 在装饰器内部使用多处理会产生错误 : can't pickle function. ..找不到

标签 python multiprocessing decorator pickle

我遇到了一个我无法解决的问题,它与多处理有关,并在装饰器中使用它。

当我调用方法时 run_in_parallels使用多处理我收到错误:

Can't pickle <function run_testcase at 0x00000000027789C8>: it's not found as __main__.run_testcase

调用发生在装饰器内部,然后就是上面提到的问题。在调用相同方法时run_in_parallels没有装饰器,一切正常。

这个问题的原因是什么?


文件: w_PythonHelper.py

desc: 函数“run_in_parallel”用于同时运行多个进程。第一种方法将结束操作并停止其他方法。

from multiprocessing import Process,Event

class ExtProcess(Process):
    def __init__(self, event,*args,**kwargs):
        self.event=event
        Process.__init__(self,*args,**kwargs)

    def run(self):
        Process.run(self)
        self.event.set()

class PythonHelper(object):
    @staticmethod
    def run_in_parallel(*functions):
        event=Event()
        processes=dict()
        for function in functions:
            fname=function[0]
            try:fargs=function[1]
            except:fargs=list()
            try:fproc=function[2]
            except:fproc=1
            for i in range(fproc):
                process=ExtProcess(event,target=fname,args=fargs)
                process.start()
                processes[process.pid]=process
        event.wait()
        for process in processes.values():
            process.terminate()
        for process in processes.values():
            process.join()

文件:w_Recorder.py

desc:函数'capture'用于抓取屏幕截图

from PIL import ImageGrab
import time

class Recorder(object):
    def capture(self):
        ImageGrab.grab().save("{f}.{e}".format(f=time.time(),e="png"))

文件: w_Decorators.py

desc: 并行运行给定函数以及类“Recorder”的方法“capture”

from w_Recorder import Recorder
from w_PythonHelper import PythonHelper

def check(function):
    def wrapper(*args):
        try:
            recorder=Recorder()
            PythonHelper.run_in_parallel([function,args],[recorder.capture])
            print("success")
        except Exception as e:
            print("failure: {}".format(e))
        return function
    return wrapper

文件:w_Logger.py

desc: 主程序(产生错误)

from w_Decorators import check
import time

class Logger(object):

    @check
    def run_testcase(self):
        # example function (runtime: 20s)
        for i in range(20):
            print("number: {}".format(i))
            time.sleep(1)

    def run_logger(self):
        self.run_testcase()


if __name__=="__main__":
    logger=Logger()
    logger.run_logger()

文件:w_Logger.py

desc: 主程序(正常运行)

from w_PythonHelper import PythonHelper
from w_Recorder import Recorder
import time

class Logger(object):

    def run_testcase(self):
        # example function (runtime: 20s)
        for i in range(20):
            print("number: {}".format(i))
            time.sleep(1)

    def run_logger(self):
        recorder=Recorder()
        PythonHelper.run_in_parallel([self.run_testcase],[recorder.capture])

if __name__=="__main__":
    logger=Logger()
    logger.run_logger()

两种情况下呈现的相同方法有何不同?


编辑: 有没有人有解决这个问题的想法(这是 Python 错误)?如果没有,也许有人知道在应用程序运行时捕获屏幕截图的好方法?

其实我发现了类似的问题:multiprocessing.Process subclass works on Linux but not Windows

答案是:To fix this, you can remove the process member. , 但我该如何为我的示例执行此操作。

调试时调用process.start()时发生错误在 run_in_parallel(*functions)


编辑2: 就像 ivan_pozdeev 写道:我可以将包装器用作函数,但不能将其用作装饰器。这个装饰器装饰了很多函数,最简单的方法是在装饰器内部使用多处理。但不幸的是我无法解决这个问题。也许有人已经解决了类似的问题。如果有任何提示,我将不胜感激。

'run_in_parallel' 功能如我所愿。两个或多个函数并行运行,第一个函数完成后强制第二个函数终止。当我调用 wrapper(function,*args) 时,函数工作正常,当我将此机制放入装饰器时,我得到'无法 pickle 函数......它找不到'错误。详情可以在上面找到

我的回溯:

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

最佳答案

您传递给 Process.__init__() 的函数在 Windows 中不可 picklable。阅读16.6 multiprocessing - Programming guidelines - Windows .

关于顶级函数的错误——我怀疑你定义它的方式,它每次生成的方式都不一样,因此在 child 中确实是“不同的对象”。 我建议传递一个简单的顶级函数,如果您真的需要这种复杂程度,它会使用反射调用 run_testcase 更新:这没有帮助

更新:

我通过取消修饰 run_testcaserun_in_parallelcapture 完成了这项工作。 @check 装饰器被替换为具有相同功能的 def wrapper(function,*args):

import traceback
def wrapper(function,*args):
    try:
        recorder=Recorder()
        PythonHelper().run_in_parallel([function,args],[recorder.capture])
        print("success")
    except Exception,e:
        print("failure: "+traceback.format_exc(10))

主要内容:

from w_Decorators import wrapper

if __name__=="__main__":
    logger=Logger()
    wrapper(logger.run_testcase)

正如我所想 - 装饰对象不可 pickle 。

关于python - 在装饰器内部使用多处理会产生错误 : can't pickle function. ..找不到,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8126654/

相关文章:

python - 如何在Python中使用转义字符?

python - 在同一层次结构中的不同类之间使用 Django ORM 语法中的 UNION

python - zeroRPC 多处理的奇怪问题

python - 为pytest测试方法编写装饰器

python - 了解类装饰器在 Python 中的工作原理

python - 如何减小 Python 创建的 txt 文件的大小?

java - 由多个进程同步轮询文件中的对象列表

python - .get() 之后多处理陷入困境

R装饰器改变输入和输出

python - 如何在 python 中编写正则表达式来匹配这个?