• python并发——多进程中的异常捕获


    在正常的python多进程中,父进程只负责将任务分发给子进程,子进程成功与否,父进程并不关心.

    但是在生产环境中,这种显然是不恰当的.通过研究我发现通过回调方法可以获取子进程的状态,然后通过一个queue将失败的子进程标记出来,就可以实现失败进程的重试,代码如下:

    import queue
    import random
    import time
    from multiprocessing import Pool
    
    q = queue.Queue()
    success_count = 0
    
    #实际运行的task方法
    def long_time_task(table_name):
        rd = random.randint(1, 10)
      #任务失败抛出异常,抛出的就是任务名称,在回调方法中可以捕获
    if rd % 2 == 0: raise Exception(table_name) global q print('ok=%s' % table_name) time.sleep(1) #成功任务计数 def success(suc): global success_count success_count = success_count + 1 #失败任务捕获 def err(error): q.put(error) if __name__ == '__main__':
      #初始化一个4个槽位线程池 p
    = Pool(4) lists = ['table_' + str(i) for i in range(1, 21)] lists_num=len(lists)
      #将任务放入队列
    for i in lists: q.put(i)
      #队列为空不一定就是所有任务完成了,可能还有在运行中的任务,所以需要两个条件满足才能退出循环
    while not q.empty() or success_count!=lists_num: if q.empty(): time.sleep(1) else: p.apply_async(long_time_task, args=(q.get(),), callback=success, error_callback=err) p.close() p.join() print('q.size=%d,success_count=%d' % (q.qsize(), success_count))

     上面的例子有时候是能运行的,但有时候不能,特别是子程序执行很快的时候while经常陷入死循环,原因是

    多进程中q.empty()不可信,异步过程中在分发任务时success_count无法获取最终结果,会导致死循环,调整后的程序如下
    import os
    import time
    from multiprocessing import Pool
    from multiprocessing import Queue
    import random
    
    q = Queue()
    success_count = 0
    
    
    # 通过回调捕获异常
    def err(error):
        q.put(error)
    
    
    def suc(success):
        global success_count
        success_count = success_count + 1
    
    
    def run_data_x(sub_table_name):
        result = os.system("echo {sub_table_name} 2".format(sub_table_name=sub_table_name))
        time.sleep(0.1)
        if result != 0 or random.randint(1, 100) == 9:
            print('failed!!!,tb=%s' % sub_table_name)
            raise Exception(sub_table_name)
    
    
    if __name__ == '__main__':
    
        p = Pool(3)
    
        table_list = ['test_0', 'test_1', 'test_2', 'test_3',
                      'test_4', 'test_5', 'test_6', 'test_7',
                      'test_8', 'test_9', 'test_10', 'test_11',
                      'test_12', 'test_13', 'test_14', 'test_15']
    
        table_list_num = len(table_list)
        for tb in table_list:
            q.put(tb)
    
        print('*********************************')
    
        # 多进程中q.empty()不可信,异步过程中success_count在分发任务时尚无法获取最终结果,会导致死循环
        # 调整为同步获取结果即可
        while success_count != table_list_num:
            # p.apply_async(run_data_x, args=(q.get(),), callback=suc, error_callback=err)
            try:
                p.apply(run_data_x, args=(q.get(True),))
                suc(1)
            except Exception as e:
                err(e)
    
        p.close()
        p.join()
        print('success_count=%d' % success_count)
  • 相关阅读:
    最新超详细VMware虚拟机安装完整教程
    Java网络编程 -- AIO异步网络编程
    Java网络编程 -- NIO非阻塞网络编程
    Java网络编程 -- BIO 阻塞式网络编程
    Java网络编程 -- 网络协议
    自定义FutureTask实现
    JDK容器类List,Set,Queue源码解读
    JDK容器类Map源码解读
    深入理解Java中的锁(三)
    深入理解Java中的锁(二)
  • 原文地址:https://www.cnblogs.com/wangbin2188/p/12627365.html
Copyright © 2020-2023  润新知