在Python

时间:2018-02-05 13:20:18

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

我确信之前已经提出了许多类似的问题,但在阅读了很多这些问题后,我仍然不太确定应该做些什么。所以,我有一个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-1s运行(如果我选择正确的参数,它们将运行相同的时间)。我不需要它们在同一时间完全启动,但理想情况下延迟应小于总运行时间的约10-20%(因此每次运行时需要少于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是否会构成任何限制?< / p>

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

2 个答案:

答案 0 :(得分:3)

使用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(),因为这有助于if __name__ == "__main__"制作新流程。

我必须说这似乎是滥用multiprocessing

答案 1 :(得分: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保留已更新并从dictp_capture()返回p_get_reading()