【问题标题】:executing two class methods at the same time in Python在 Python 中同时执行两个类方法
【发布时间】:2018-07-15 08:48:02
【问题描述】:

我相信之前已经有人问过很多类似的问题,但是在阅读了很多之后,我仍然不太确定我应该做什么。所以,我有一个 Python 脚本来控制一些外部仪器(相机和功率计)。我通过使用 ctypes 调用 .dll 文件中的 C 函数为这两种仪器编写了类。现在它看起来像这样:

for i in range(10):
    power_reading = newport.get_reading(N=100,interval=1) # take power meter reading
    img = camera.capture(N=10)
    value = image_processing(img) # analyze the img (ndarray) to get some values
    results.append([power_reading,value]) # add both results to a list

我想同时开始执行前两行。 newport.get_readingcamera.capture 都需要大约 100ms-1 秒才能运行(如果我选择正确的参数,它们将同时运行)。我不需要它们在完全相同的时间启动,但理想情况下,延迟应该小于总运行时间的 10-20% 左右(因此每次运行大约需要 1 秒时延迟小于 0.2 秒)。根据我的阅读,我可以使用multiprocessing 模块。所以我根据post尝试这样的事情:

def p_get_reading(newport,N,interval,return_dict):
    reading = newport.get_reading(N,interval,return_dict)
    return_dict['power_meter'] = reading

def p_capture(camera,N,return_dict):
    img = camera.capture(N)
    return_dict['image'] = img

for i in range(10):
    manager = multiprocessing.Manager()
    return_dict = manager.dict()
    p = multiprocessing.Process(target=p_capture, args=(camera,10))
    p.start()
    p2 = multiprocessing.Process(target=p_get_reading, args=(newport,100,1))
    p2.start()
    p.join()
    p2.join()
    print(return_dict)

我有几个问题/疑问:

  1. 我需要从两个函数调用中获取返回值。使用我目前的方法,return_dict 只显示capture_img 的条目,但不显示功率计读数,这是为什么呢?它还读到我可以使用Queue,对于我目前的目的,最好的方法是什么?

  2. 我如何知道这两个函数是否确实同时开始运行?我正在考虑使用time 模块来记录这两个函数的开始和结束时间,也许使用一些包装函数来记录时间,但是使用multiprocessing 会有什么限制吗?

  3. 我通常在 IDE (spyder) 上运行我的代码,根据我所阅读的内容,我需要在命令提示符下运行以查看输出(我在函数中有一些打印语句用于调试目的)。我还能在 IDE 中同时运行这两个函数吗?

【问题讨论】:

  • Process 对象的创建可能会影响您的实验:时间可能很长。因此,您可能需要先创建流程,并且只有在创建它们之后,它们才能被释放以完成它们的工作。某种形式的互斥锁或锁可能会做到这一点。或者Queue 可以提供帮助。
  • 1.这似乎是您网站上阅读功能的问题,因为我无法重现它。也许添加代码,以便我们可以重现它。 2. 应该没有问题。多处理只需要一个可调用的,所以它不关心包装器,(但不要使用全局变量)。 time.time 也不受限制。 3. 我的想法为零,因为我使用 pycharm,它也可以在 ide 中工作。
  • 1.试试dict.update({'key':'value'}),它可能有助于异步处理; 2. 您可以使用time-module(请参阅here),但我推荐它,因为您在执行此操作时“浪费”了更多时间; 3.尝试使用sys.stdout.write(); 4.正如quamrana所说,首先创建pp2,然后执行:p.start()p2.start()

标签: python python-3.x multiprocessing python-multiprocessing python-multithreading


【解决方案1】:

回答您的第一个问题如果您以正常方式进行操作,则绝对不会,但如果您希望这样做,则可以。否,因为目标函数无法使用return 与生成线程通信。一种方法是使用队列和包装函数,如下所示:

from threading import Thread 
from Queue import Queue 

def p_get_reading(newport,N,interval,return_dict):
   reading = newport.get_reading(N,interval,return_dict)
   return_dict.update({'power_meter': reading})
   return return_dict

def p_capture(camera,N,return_dict):
   img = camera.capture(N) 
   return_dict.update({'image': img})
   return return_dict

def wrapper1(func, arg1, arg2, queue):
   queue.put(func(arg1, arg2)) 

def wrapper2(func, arg1, arg2, arg3, queue):
    queue.put(func(arg1, arg2, arg3)) 

q = Queue()
Thread(target=wrapper1, args=(p_capture, camera, 10 , q)).start() 
Thread(target=wrapper2, args=(p_get_reading, newport, 100, 1, q)).start() 

现在q 保存从p_capture()p_get_reading() 更新和返回的dict

【讨论】:

  • 但我是否仍然可以与threading 同步(至少在理论上)?我尝试将start_time = time.perf_counter()放在reading=newport.get_reading()img=camera_capture之前,并通过return_dict输出开始时间。时间延迟大约是0.004s(在我的容忍范围内),但是我应该相信这个数字多少呢? reading=newport.get_reading()img=camera_capture 这两条线实际上会以更大的时间延迟开始吗?
  • 您可以使用threading 执行多个I/O 任务或执行多个功能。从理论上讲,它们是同步的并同时执行,但肯定会有时间延迟。如果您使用的是多核系统,则可以利用它。 multiprocessingconcurrent.futures.ProcessPoolExecutor 可能会有所帮助。
【解决方案2】:

使用Lock 可能有助于同步:

import multiprocessing

def p_get_reading(newport, N, interval, lock, return_dict):
    lock.acquire()
    lock.release()
    reading = newport.get_reading(N, interval)
    return_dict['power_meter'] = reading

def p_capture(camera, N, lock, return_dict):
    lock.acquire()
    lock.release()
    img = camera.capture(N)
    return_dict['image'] = img

if __name__ == "__main__":    
    for i in range(10):
        manager = multiprocessing.Manager()
        return_dict = manager.dict()
        lock = multiprocessing.Lock()
        lock.acquire()
        p = multiprocessing.Process(target=p_capture, args=(camera,10,lock,return_dict))
        p.start()
        p2 = multiprocessing.Process(target=p_get_reading, args=(newport,100,1,lock,return_dict))
        p2.start()
        lock.release()
        p.join()
        p2.join()
        print(return_dict)

现在可以创建两个Process 对象并以任意顺序创建start()ed,因为主例程已经获得了锁。一旦释放,这两个进程将相互竞争以获取和释放锁,并几乎同时准备好。

另外,请注意if __name__ == "__main__" 的使用,因为这有助于multiprocessing 创建新进程。

我必须说这似乎是对Lock的滥用

【讨论】:

    猜你喜欢
    • 2011-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-02
    • 1970-01-01
    • 2022-01-10
    • 2011-12-16
    • 1970-01-01
    相关资源
    最近更新 更多