【问题标题】:Pickling errors when using multiprocessing使用多处理时的酸洗错误
【发布时间】:2018-07-26 07:07:24
【问题描述】:

我想同时控制和运行两台实验室设备(至少同时启动它们),所以我使用了多处理模块。

from myLabModule import Newport1936R
from myLabModule import DCx_camera
from multiprocessing import Process, Queue

def multiprocess_camera(camera, shots_per_img, queue, delay):
    time.sleep(delay)
    img, camera_time = camera.capture(shots_per_img, np.float64, True) #img is a 2x2 ndarray
    results = [camera_time[0], camera_time[1], img, 'img']
    queue.put(results)

def multiprocess_power(newport, interval, N, queue, delay):
    time.sleep(delay)
    power_reading, newport_time = newport.get_power(interval, N, True)
    results = [newport_time[0], newport_time[1], power_reading, 'power']
    queue.put(results)

if __name__ == "__main__":
    thorcam = DCx_camera()
    newport = Newport1936R()
    queue = Queue()
    p1 = Process(target=multiprocess_camera, args=(thorcam,10,queue,0))
    p2 = Process(target=multiprocess_power, args=(newport,1,10,queue,0))
    p1.start()
    p2.start()
    p1.join()
    p2.join()
    results = []
    results.append(queue.get())
    results.append(queue.get())

当我运行代码时,我收到以下错误:AttributeError: Can't pickle local object 'CDLL.__init__.<locals>._FuncPtr'。我读了这个post,似乎它与变量的范围有关(我将另一个模块中定义的两个类传递给函数,函数基本上运行类的方法)。我不确定究竟是哪个部分导致了问题。我应该如何修改代码以使其工作?

【问题讨论】:

  • 为什么你必须创建实例然后转发它们只是为了使用转发参数调用它们的方法?看起来这就是问题所在,如果这不是严格要求,为什么不在函数中创建实例?
  • @ikac 抱歉,我不太明白你的意思。正如我所说,我最终想要实现的是同时执行thorcam.capture()newport.get_power()(使用多处理)并获取它们的返回值。我刚刚查看了一些相关的帖子,似乎制作一个单独的函数是这样做的方法,当然我对其他更好的方法持开放态度。
  • 那么你为什么不在目标方法中创建实例呢?如果实际用例与此示例类似,则您没有代码引用实例 thorcamnewport 波纹管进程已启动。
  • 是指在当前脚本中定义thorcamnewport 吗?我可以这样做,唯一的问题是我为thorcamnewport 编写的模块有几百行长,所以我认为如果我将它们保存为单独的文件看起来会更简洁。是否可以只用几行重新定义类并将实际代码引用到单独的文件中?
  • 我的意思是完全不用担心酸洗。在这里,当您将实例作为目标的参数传递时执行酸洗,例如args=(thorcam,10,queue,0)thorcam 必须腌制,我不确定DCx_camera 是如何实现的。

标签: python-3.x class multiprocessing pickle python-multiprocessing


【解决方案1】:

在这种情况下,当将参数传递给target 方法时会执行酸洗,该方法将作为新(子)进程执行。

确切地说,我不确定是否可以酸洗 DCx_cameraNewport1936R 的实例。取决于这些类的定义方式,但查看错误消息我想你不能。这就是为什么您可以尝试根本不传递这些引用的原因。通过示例,您似乎不需要。

这是我期望的工作:

from myLabModule import Newport1936R
from myLabModule import DCx_camera
from multiprocessing import Process, Queue

def multiprocess_camera(shots_per_img, queue, delay):
    camera = DCx_camera()
    time.sleep(delay)
    img, camera_time = camera.capture(shots_per_img, np.float64, True) #img is a 2x2 ndarray
    results = [camera_time[0], camera_time[1], img, 'img']
    queue.put(results)

def multiprocess_power(interval, N, queue, delay):
    newport = Newport1936R()
    time.sleep(delay)
    power_reading, newport_time = newport.get_power(interval, N, True)
    results = [newport_time[0], newport_time[1], power_reading, 'power']
    queue.put(results)

if __name__ == "__main__":
    queue = Queue()
    p1 = Process(target=multiprocess_camera, args=(10,queue,0))
    p2 = Process(target=multiprocess_power, args=(1,10,queue,0))
    p1.start()
    p2.start()
    p1.join()
    p2.join()
    results = []
    results.append(queue.get())
    results.append(queue.get())

这是不是可以让你得到想要的结果?

根据link,还有一个替代方案。

比pickle/unpickle更好继承

但是,通常应该避免 使用管道或队列将共享对象发送到其他进程。 相反,您应该安排程序,以便需要 访问在别处创建的共享资源可以从 祖先进程。

这就是为什么我认为您甚至可以拥有引用 DCx_cameraNewport1936R 实例的全局变量,然后在这两个目标方法中使用它们。

【讨论】:

    猜你喜欢
    • 2021-04-29
    • 1970-01-01
    • 2015-04-07
    • 1970-01-01
    • 2014-09-15
    • 2017-03-30
    • 2019-05-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多