Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/293.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Worker中的Python多处理和异常处理_Python_Exception_Error Handling_Parallel Processing_Multiprocessing - Fatal编程技术网

Worker中的Python多处理和异常处理

Worker中的Python多处理和异常处理,python,exception,error-handling,parallel-processing,multiprocessing,Python,Exception,Error Handling,Parallel Processing,Multiprocessing,我将python多处理库用于一个算法,在该算法中,我让许多工作人员处理某些数据并将结果返回给父进程。我使用multiprocessing.Queue将作业传递给工人,然后使用第二个队列收集结果 这一切都很好,直到工作人员无法处理某些数据块。在下面的简化示例中,每个工人有两个阶段: 初始化-可能会失败,在这种情况下,工作进程应该被销毁 数据处理-处理一个数据块可能会失败,在这种情况下,工作人员应该跳过该数据块并继续处理下一个数据 当这两个阶段中的任何一个都失败时,脚本完成后就会出现死锁。此代码

我将python多处理库用于一个算法,在该算法中,我让许多工作人员处理某些数据并将结果返回给父进程。我使用multiprocessing.Queue将作业传递给工人,然后使用第二个队列收集结果

这一切都很好,直到工作人员无法处理某些数据块。在下面的简化示例中,每个工人有两个阶段:

  • 初始化-可能会失败,在这种情况下,工作进程应该被销毁
  • 数据处理-处理一个数据块可能会失败,在这种情况下,工作人员应该跳过该数据块并继续处理下一个数据
当这两个阶段中的任何一个都失败时,脚本完成后就会出现死锁。此代码模拟我的问题:

import multiprocessing as mp
import random

workers_count = 5
# Probability of failure, change to simulate failures
fail_init_p = 0.2
fail_job_p = 0.3


#========= Worker =========
def do_work(job_state, arg):
    if random.random() < fail_job_p:
        raise Exception("Job failed")
    return "job %d processed %d" % (job_state, arg)

def init(args):
    if random.random() < fail_init_p:
        raise Exception("Worker init failed")
    return args

def worker_function(args, jobs_queue, result_queue):
    # INIT
    # What to do when init() fails?
    try:
        state = init(args)
    except:
        print "!Worker %d init fail" % args
        return
    # DO WORK
    # Process data in the jobs queue
    for job in iter(jobs_queue.get, None):
        try:
            # Can throw an exception!
            result = do_work(state, job)
            result_queue.put(result)
        except:
            print "!Job %d failed, skip..." % job
        finally:
            jobs_queue.task_done()
    # Telling that we are done with processing stop token
    jobs_queue.task_done()



#========= Parent =========
jobs = mp.JoinableQueue()
results = mp.Queue()
for i in range(workers_count):
    mp.Process(target=worker_function, args=(i, jobs, results)).start()

# Populate jobs queue
results_to_expect = 0
for j in range(30):
    jobs.put(j)
    results_to_expect += 1

# Collecting the results
# What if some workers failed to process the job and we have
# less results than expected
for r in range(results_to_expect):
    result = results.get()
    print result

#Signal all workers to finish
for i in range(workers_count):
    jobs.put(None)

#Wait for them to finish
jobs.join()
将多处理导入为mp
随机输入
工人人数=5
#失效概率、模拟失效的变更
失败初始p=0.2
作业失败\u p=0.3
#==========工人=========
def do_工作(作业状态,arg):
如果random.random()
关于该代码,我有两个问题:

  • init()
    失败时,如何检测工作进程是否无效,而不是等待它完成
  • do_work()
    失败时,如何通知父进程结果队列中预期的结果会减少
    谢谢你的帮助

    我稍微修改了您的代码以使其正常工作(请参见下面的解释)

    将多处理导入为mp
    随机输入
    工人人数=5
    #失效概率、模拟失效的变更
    失败初始p=0.5
    作业失败\u p=0.4
    #==========工人=========
    def do_工作(作业状态,arg):
    如果random.random()
    我的变化:

  • 作业
    更改为普通的
    队列
    (而不是
    可接合队列
  • 工作人员现在将特殊结果字符串“init failed”和“job failed”传回
  • 只要特定条件有效,主过程监控上述特殊结果
  • 最后,不管你有多少员工,都要提出“停止”请求(即
    None
    jobs)。请注意,并非所有这些都可以从队列中提取(以防工作进程初始化失败)

  • 顺便说一句,您的原始代码很好,并且易于使用。随机概率位非常酷。

    或者您可以将一个元组
    (结果,错误)
    (成功时错误为无)放入结果队列,以避免带内错误通信。
    import multiprocessing as mp
    import random
    
    workers_count = 5
    # Probability of failure, change to simulate failures
    fail_init_p = 0.5
    fail_job_p = 0.4
    
    
    #========= Worker =========
    def do_work(job_state, arg):
        if random.random() < fail_job_p:
            raise Exception("Job failed")
        return "job %d processed %d" % (job_state, arg)
    
    def init(args):
        if random.random() < fail_init_p:
            raise Exception("Worker init failed")
        return args
    
    def worker_function(args, jobs_queue, result_queue):
        # INIT
        # What to do when init() fails?
        try:
            state = init(args)
        except:
            print "!Worker %d init fail" % args
            result_queue.put('init failed')
            return
        # DO WORK
        # Process data in the jobs queue
        for job in iter(jobs_queue.get, None):
            try:
                # Can throw an exception!
                result = do_work(state, job)
                result_queue.put(result)
            except:
                print "!Job %d failed, skip..." % job
                result_queue.put('job failed')
    
    
    #========= Parent =========
    jobs = mp.Queue()
    results = mp.Queue()
    for i in range(workers_count):
        mp.Process(target=worker_function, args=(i, jobs, results)).start()
    
    # Populate jobs queue
    results_to_expect = 0
    for j in range(30):
        jobs.put(j)
        results_to_expect += 1
    
    init_failures = 0
    job_failures = 0
    successes = 0
    while job_failures + successes < 30 and init_failures < workers_count:
        result = results.get()
        init_failures += int(result == 'init failed')
        job_failures += int(result == 'job failed')
        successes += int(result != 'init failed' and result != 'job failed')
        #print init_failures, job_failures, successes
    
    for ii in range(workers_count):
        jobs.put(None)