Python多重处理:如何衡量工作程序中子进程的运行时间?

时间:2019-01-15 00:42:29

标签: python multiprocessing

work_one()像这样:

def work_one(program_path):
    task = subprocess.Popen("./" + program_path, shell=True)
    t = 0
    while True:
        ret = task.poll()
        if ret != None or t >= T: # T is the max time we allow for 'task'
            break;
        else:
            t += 0.05
            time.sleep(0.05)
    return t

有许多此类程序可馈送给work_one()。当这些程序按顺序运行时,每个work_one()报告的时间是每个程序运行时的可靠粗略度量。


但是,假设我们有一个multiprocessing.Pool()实例,其中包含20个工作线程pool,我们这样调用函数:

   def work_all(programs):
       pool = multiprocessing.Pool(20)
       ts = pool.map(work_one, programs)
       return ts

现在,work_all()报告的运行时度量大约是连续work_one()报告的运行时度量的20倍。

这是合理的,因为在work_one()中,当工作进程将0.05添加到t并屈服(通过调用time.sleep())时,它可能无法屈服到它正在管理的子流程(task)(不一样,只有一个工人时);取而代之的是,操作系统可能决定将CPU交给另一个并发工作进程。因此,worker_one()内的迭代次数可能是task完成之前的20倍。

问题:

  1. 知道work_one()可能正在同时运行,如何正确实施work_one()以获得良好的运行时度量?
  2. 如果子流程work_one()task秒内未完成,我也希望T早点返回,因此os.wait*()函数似乎不是一个好的解决方案,因为它们会阻塞父进程。

1 个答案:

答案 0 :(得分:1)

一个过程有几个相关的时间;这是全部获取方法(请参见What do 'real', 'user' and 'sys' mean in the output of time(1)?; tl; dr:您的进程占用的CPU总时间为user_time + system_time):

import time
import os
import subprocess

def work_one(program_path):
    start = time.perf_counter()
    task = subprocess.Popen(program_path, shell=True)
    pid, exit_status, resource_usage = os.wait4(task.pid, 0)
    end = time.perf_counter()
    real_time = end - start
    user_time = resource_usage.ru_utime
    system_time = resource_usage.ru_stime
    return (real_time, user_time, system_time)

编辑:已修改以提供超时。但是,我无法让resource.getrusage在测试用例中返回零。也许需要更长的时间,或者我做错了事。

def timeout_handler(signum, frame):
    raise TimeoutError()

timeout = 2

def work_one(program_path):
    try:
        timed_out = False
        signal.signal(signal.SIGALRM, timeout_handler)
        signal.alarm(timeout)
        start = time.perf_counter()
        task = subprocess.Popen(program_path, shell=True)
        pid, exit_status, resource_usage = os.wait4(task.pid, 0)
    except TimeoutError:
        timed_out = True
        resource_usage = resource.getrusage(resource.RUSAGE_CHILDREN)
        os.kill(task.pid, signal.SIGTERM)
    finally:
        signal.alarm(0)
    end = time.perf_counter()
    real_time = end - start
    user_time = resource_usage.ru_utime
    system_time = resource_usage.ru_stime
    return (timed_out, real_time, user_time, system_time)