zoukankan      html  css  js  c++  java
  • 记一个在docker中运行多线程event_loop.run_forever()的bug

    问题简介

    我写爬虫,用到了asyncio相关的事件循环,新建了一个线程去run_forever(),在docker中运行。后来程序有异常,主线程挂了,但是竟然不报错。查了很久,才找出来。
    如果你新建一个线程去运行一般的死循环,主线程出错退出,是会报错的,虽然子线程还会继续运行。
    如果你新建一个线程去运行event_loop.run_forever(),主线程出异常退出,没有任何错误提示,子线程一样继续运行。

    解决办法

    我查了很久也不知道为什么,在本地跑,一切正常。测试程序如下:

    import asyncio
    import logging
    from threading import Thread
    
    
    logging.basicConfig(level=logging.INFO, format='[%(asctime)s] - %(levelname)s in %(filename)s: %(message)s')
    logger = logging.getLogger(__name__)
    
    
    def start_loop(event_loop):
        """start run_forever"""
        asyncio.set_event_loop(event_loop)
        event_loop.run_forever()
    
    
    def get_event_loop():
        """new and return event_loop"""
        event_loop = asyncio.new_event_loop()
        t0 = Thread(target=start_loop, args=(event_loop,))
        t0.start()
        return event_loop
    
    
    if __name__ == '__main__':
        loop = get_event_loop()
    
        logger.info('make error')
        raise TimeoutError('sfasf')
    
    """
    [2019-04-16 13:40:46,101] - INFO in docker_test.py: make error
    Traceback (most recent call last):
      File "D:/Code/python/concurrent_crawler/test/docker_test/docker_test.py", line 38, in <module>
        raise TimeoutError('sfasf')
    TimeoutError: sfasf
    """
    

    如果在docker中就没有任何错误提示,最后解决办法如下

    import asyncio
    import logging
    from threading import Thread
    
    
    logging.basicConfig(level=logging.INFO, format='[%(asctime)s] - %(levelname)s in %(filename)s: %(message)s')
    logger = logging.getLogger(__name__)
    
    
    def start_loop(event_loop):
        """start run_forever"""
        asyncio.set_event_loop(event_loop)
        event_loop.run_forever()
    
    
    def get_event_loop():
        """new and return event_loop"""
        event_loop = asyncio.new_event_loop()
        t0 = Thread(target=start_loop, args=(event_loop,))
        t0.setDaemon(True)  # 随着主线程结束而结束
        t0.start()
        return event_loop
    
    
    if __name__ == '__main__':
        loop = get_event_loop()
    
        logger.info('make error')
        raise TimeoutError('sfasf')
    

    利用线程的setDaemon(True)方法,结束子线程。这样才会输出出来!
    这个问题我放到stackoverflow了link

  • 相关阅读:
    一文带你看清HTTP所有概念
    程序员不得不了解的硬核知识大全
    看完这篇HTTP,跟面试官扯皮就没问题了
    ReentrantLock 源码分析从入门到入土
    计算机网络的核心概念
    Kafka 的这些原理你知道吗
    2019 我是怎么熬过来的?
    不懂什么是锁?看看这篇你就明白了
    机器学习——方差、协方差与皮尔逊值
    最小生成树的本质是什么?Prim算法道破天机
  • 原文地址:https://www.cnblogs.com/haoabcd2010/p/10716542.html
Copyright © 2011-2022 走看看