zoukankan      html  css  js  c++  java
  • 一文说懂join和setDaemon

    一文说懂join和setDaemon

     最精简的知识点:

    1、主线程退出,子线程还可以在跑。线程之间都无关

    2、守护线程会被其他最后一个线程或主线程终止。监听谁 就把谁设置守护线程

    3、想在主线程结束前跑完子线程,用join().

    ----------------------------------

    这里有个小疑问,既然加不加join子线程都会跑完,为什么还加join。因为有些线程之间需要输出参数给其余函数用,所以得等某个函数线程跑完才能执行主线程。

    1 先记住三句话

    主线程退出,进程等待所有子线程执行完毕后才结束

    主线程结束后进程不等待守护线程完成,立即结束     setDaemon(True)

    主线程等待子线程完成后结束 join

    2 作用

    1)想先停主线程,先跑子现程用join

    2)想监听某个函数,超时后关闭这个函数,设立这个函数的线程为守护线程。

    3)最常见的连用方式  thr.setDaemon(True),  后面thr.join()   注意不用加时间。或者加一个超时时间,超时时间一到主线程执行,执行结束后,进程自动关闭守护子线程。

    仔细理解下面两个功能代码:

    1 超时器

    import time
    #from threading import Thread
    import threading
    import sys
    
    class KThread(threading.Thread):
        """A subclass of threading.Thread, with a kill()
        method.
        
        Come from:
        Kill a thread in Python: 
        http://mail.python.org/pipermail/python-list/2004-May/260937.html
        """
        def __init__(self, *args, **kwargs):
            threading.Thread.__init__(self, *args, **kwargs)
            self.killed = False
    
        def start(self):
            """Start the thread."""
            self.__run_backup = self.run
            self.run = self.__run      # Force the Thread to install our trace.
            threading.Thread.start(self)
    
        def __run(self):
            """Hacked run function, which installs the
            trace."""
            sys.settrace(self.globaltrace)
            self.__run_backup()
            self.run = self.__run_backup
    
        def globaltrace(self, frame, why, arg):
            if why == 'call':
              return self.localtrace
            else:
              return None
    
        def localtrace(self, frame, why, arg):
            if self.killed:
              if why == 'line':
                raise SystemExit()
            return self.localtrace
    
        def kill(self):
            self.killed = True
    
    class Timeout(Exception):
        """function run timeout"""
        
    def timeout(seconds = 3):
        def timeout_decorator(func):        
            def _new_func(oldfunc, result, oldfunc_args, oldfunc_kwargs):
                result.append(oldfunc(*oldfunc_args, **oldfunc_kwargs))
            
            def _(*args, **kwargs):
                result = []
                new_kwargs = { # create new args for _new_func, because we want to get the func return val to result list
                    'oldfunc': func,
                    'result': result,
                    'oldfunc_args': args,
                    'oldfunc_kwargs': kwargs
                }
                thd = KThread(target=_new_func, args=(), kwargs=new_kwargs)
                thd.setDaemon(True)
                thd.start()
                thd.join(seconds)
                #alive = thd.isAlive() 版本isAlive转为is_alive
                alive = thd.is_alive()
                thd.kill()
                #try:
                    #if alive:
                        #raise Timeout(u'function run too long, timeout %d seconds.' % seconds)
                    #else:
                        #if len(result) == 0:
                            #raise Exception("TESTCASE FAILED")
                        #else:
                            #return result[0]
                #except Exception as e:
                    #print("toolong",e)
                    
                if alive:
                    raise Timeout(u'function run too long, timeout %d seconds.' % seconds)
                else:
                    if len(result) == 0:
                        raise Exception("TESTCASE FAILED")
                    else:
                        return result[0]
            _.__name__ = func.__name__
            _.__doc__ = func.__doc__
            return _
        return timeout_decorator
    
    @timeout(3)
    def fun():
        print("111231111111---")
        time.sleep(100)
        print("===")
    @timeout(3)
    def fun0():
        print("11111")
        time.sleep(2)
        
        print("end")
        return 10001
        
    #fun()
    #print(fun0())
    def tr(sce):
        def wrap(fun):
            def deco():
                print("-=====", sce)
                fun()
                print("_==========")
            return deco
        return wrap
    @tr(3)
    def runt():
        print("run111111111===",runt.__name__)
    
    #runt()

    2 监听某个目录下文件是否生成

    import os
    import time
    import threading
    RET=0
    def wrap(func):
        def lis_file(dirname,name,epch=30,tim=0.1):
            print("===lis_file")
            print("epch===",epch)
            global RET
            print("RET===",RET)
            c=1
            while c<=epch:
                print("=== %s==="%c)
                file_list = os.listdir(dirname)
                if name in file_list:
                    
                    RET=True
                    print("===",RET)
                    return RET
                time.sleep(tim)
                
                c+=1
            print("c=====",c)
            RET=False
            return RET
        def _(*args):
            lis = threading.Thread(target=lis_file,args=(args))
            ft = threading.Thread(target=func,args=(args))
            #lis.setDaemon(False)
            # 想设立守护线程,即哪个函数需要被监控就设立哪个函数为守护现程。
            # 这个守护现程一定掩护所有现程子主线程全部跑完才能结束。
            ft.setDaemon(True)
            lis.start()
            ft.start()
            #func(*args)
            # join加入容器,会先跑容器中的线程,然后再回到主线程
            # join 1 表示主线程等子线程1s后结束,然后子线程还继续跑
            # 画出现程关系图 join为主现程一直等待子线程
            # 不叫join 为 主线程跑 子线程跑 子现程跑  主线程结束,子现程结束
            ft.join()
            print("============")
        return _
    
    @wrap
    def fun(dirname,name,epch=30,tim=0.1):
        print("start===")
        time.sleep(10)
        with open("shiyan.txt","w") as f:
            f.write("===")
        print("end===")
    
    d=r"C:UsersdevevfDocumentsAItestshiyan"
    name=r"shiyan.txt"
    fun(d,name,30,0.1)

    3 为了验证setDaemon

    注意 跑带有setDaemon时一定在cmd执行py脚本,在ide中没有setDaemon效果

    import threading
    import time
    
    
    def child_thread1():
        
        for i in range(10):
            time.sleep(1)
            with open("setd111.txt","a") as f:
                f.write(str(i))
            print('child_thread1_running...')
    
    
    def child_thread2():
        with open("setd222.txt","a") as f:
            for i in range(1):
                time.sleep(1)
                f.write(str(i))
                print('child_thread2_running...')
    
    
    def parent_thread():
        print('parent_thread_running...')
        thread1 = threading.Thread(target=child_thread1)
        thread2 = threading.Thread(target=child_thread2)
        # 注意ide体现不出来,在cmd里面执行会明显
        # 守护线程,当前进程结束线程立即结束,或者是主线程结束立即结束
        # 主线程结束后进程不等待守护线程完成,立即结束
        # 实验为 守护线程或长或短都不影响主线程的结束
        # 守护线程 一定等所有线程结束才能结束
        # 两个守护线程 按照谁的进度,谁都不按照,只是按照主线程
        thread1.setDaemon(True)
        #thread2.setDaemon(True)
        thread1.start()
        thread2.start()
        print('parent_thread_exit...')
        time.sleep(1)
        with open("main_file.txt","w") as f:
            f.write("mainfile")
        print("main bu shou yingxiang====yanzheng kongzhi jincheng")
    
    
    if __name__ == "__main__":
        parent_thread()
        
    

      

    ---------------------------------------------------------------------------------------------------------

    参考下文,若精炼内容没有理解清楚请看参考,例子都很经典。

    python主线程与子线程的结束顺序

     

    引用自 主线程退出对子线程的影响--YuanLi 的一段话:

    对于程序来说,如果主进程在子进程还未结束时就已经退出,那么Linux内核会将子进程的父进程ID改为1(也就是init进程),当子进程结束后会由init进程来回收该子进程。

    主线程退出后子线程的状态依赖于它所在的进程,如果进程没有退出的话子线程依然正常运转。如果进程退出了,那么它所有的线程都会退出,所以子线程也就退出了。

    主线程退出,进程等待所有子线程执行完毕后才结束

    进程启动后会默认产生一个主线程,默认情况下主线程创建的子线程都不是守护线程(setDaemon(False))。因此主线程结束后,子线程会继续执行,进程会等待所有子线程执行完毕后才结束

    所有线程共享一个终端输出(线程所属进程的终端)

    import threading
    import time
    
    
    def child_thread1():
        for i in range(100):
            time.sleep(1)
            print('child_thread1_running...')
    
    
    def parent_thread():
        print('parent_thread_running...')
        thread1 = threading.Thread(target=child_thread1)
        thread1.start()
        print('parent_thread_exit...')
    
    
    if __name__ == "__main__":
        parent_thread()
    

    输出为:

    parent_thread_running...
    parent_thread_exit...
    child_thread1_running...
    child_thread1_running...
    child_thread1_running...
    child_thread1_running...
    ...
    

    可见父线程结束后,子线程仍在运行,此时结束进程,子线程才会被终止

    主线程结束后进程不等待守护线程完成,立即结束

    当设置一个线程为守护线程时,此线程所属进程不会等待此线程运行结束,进程将立即结束

    import threading
    import time
    
    
    def child_thread1():
        for i in range(100):
            time.sleep(1)
            print('child_thread1_running...')
    
    
    def child_thread2():
        for i in range(5):
            time.sleep(1)
            print('child_thread2_running...')
    
    
    def parent_thread():
        print('parent_thread_running...')
        thread1 = threading.Thread(target=child_thread1)
        thread2 = threading.Thread(target=child_thread2)
        thread1.setDaemon(True)
        thread1.start()
        thread2.start()
        print('parent_thread_exit...')
    
    
    if __name__ == "__main__":
        parent_thread()
    

    输出:

    parent_thread_running...
    parent_thread_exit...
    child_thread1_running...child_thread2_running...
    
    child_thread1_running...child_thread2_running...
    
    child_thread1_running...child_thread2_running...
    
    child_thread1_running...child_thread2_running...
    
    child_thread2_running...child_thread1_running...
    
    Process finished with exit code 0
    

    thread1是守护线程,thread2非守护线程,因此,进程会等待thread2完成后结束,而不会等待thread1完成

    注意:子线程会继承父线程中daemon的值,即守护线程开启的子线程仍是守护线程

    主线程等待子线程完成后结束

    在线程A中使用B.join()表示线程A在调用join()处被阻塞,且要等待线程B的完成才能继续执行

    import threading
    import time
    
    
    def child_thread1():
        for i in range(10):
            time.sleep(1)
            print('child_thread1_running...')
    
    
    def child_thread2():
        for i in range(5):
            time.sleep(1)
            print('child_thread2_running...')
    
    
    def parent_thread():
        print('parent_thread_running...')
        thread1 = threading.Thread(target=child_thread1)
        thread2 = threading.Thread(target=child_thread2)
        thread1.setDaemon(True)
        thread2.setDaemon(True)
        thread1.start()
        thread2.start()
        thread2.join()
        1/0
        thread1.join()
        print('parent_thread_exit...')
    
    
    if __name__ == "__main__":
        parent_thread()
    

    输出:

    parent_thread_running...
    child_thread1_running...
    child_thread2_running...
    child_thread1_running...
    child_thread2_running...
    child_thread1_running...
    child_thread2_running...
    child_thread1_running...
    child_thread2_running...
    child_thread1_running...
    child_thread2_running...
    Traceback (most recent call last):
      File "E:/test_thread.py", line 31, in <module>
        parent_thread()
      File "E:/test_thread.py", line 25, in parent_thread
        1/0
    ZeroDivisionError: integer division or modulo by zero
    

    主线程在执行到thread2.join()时被阻塞,等待thread2结束后才会执行下一句

    1/0 会使主线程报错退出,且thread1设置了daemon=True,因此主线程意外退出时thread1也会立即结束。thread1.join()没有被主线程执行

  • 相关阅读:
    Python编码规范12-访问控制--访问控制
    Python编码规范11-命名规范--命名约定
    Python编码规范10-命名规范--命名规范
    Python编码规范09-注释--文档注释
    Python编码规范08-注释--代码注释
    Python编码规范07-基础规范--文件和sockets
    Python编码规范06-基础规范--字符串
    Python编码规范05-基础规范--文档字符串(docstring)
    Python编码规范04-基础规范--空格
    Python编码规范03-基础规范--import语句
  • 原文地址:https://www.cnblogs.com/lx63blog/p/14037345.html
Copyright © 2011-2022 走看看