Python3之并发(三)---线程生命周期和控制
一、 线程的生命周期
当线程被创建并启动以后,它既不是一启动就进入执行状态,也不是一直处于执行状态,线程状态会多次在运行、就绪之间转换
线程的五种状态
新建(New) 当程序创建了一个Thread对象或Thread子类的对象后,该线程就处于新建状态,程序也不会立即执行该线程 就绪(Ready) 当调用 start() 方法之后,该线程就处于就绪状态(相当于等待执行) 处于就绪状态的线程并没有开始运行,仅仅表示该线程可以运行了,该线程何时开始运行取决于CPU调度 当线程对象调用 start() 方法之后,再次调用 start() 方法会引发 RuntimeError 异常 运行(Running) 如果处于就绪状态的线程获得了CPU的调度,线程开始执行 run() 方法,此时该线程处于运行状态 若系统只有一个CPU,那么任何时刻都只有一个线程处于运行状态 若系统由多个CPU,将会有多个线程并行运行 堵塞(Blocked) 当CPU对多个线程进行调度时,获得CPU调度却没有执行完毕的线程,就会进入阻塞状态 线程堵塞后,其他线程获得执行机会,但具体是哪个线程被指执行,取决于CPU调度 被堵塞的线程会在解决了线程堵塞遇到的问题之后由阻塞状态转到就绪状态,继续等待CPU调度 线程堵塞的四种方式 1 线程调用sleep()方法主动放弃所占用的资源 2 线程调用了一个阻塞式I/O方法(如等待用户输入),在该方法返回之前 3 线程试图获得一个锁对象,但锁对象正被其他线程所持有 4 线程线程调用wait()方法,在等待某个通知或某种特定的满足条件 死亡(Dead) 线程执行结束后将处于死亡状态 线程执行结束包括: 线程执行完线程执行体正常结束 线程执行过程引发异常(Exception)或者错误(Error) 主线程死亡,并不意味着所有线程全部死亡,即主线程死亡,并不意味着所有线程全部死亡;反之也是如此 对死亡的线程调用 start()方法会引发 RuntimeError 异常
二、线程控制
Thread.join(timeout=number) 等待 join() 调用的Thread子线程终止的时间 会堵塞当前线程,直到 join() 调用的Thread子线程终止(timeout=None)或者超时(timeout=number) timeout: jion() 调用的线程的超时时间,float类型,默认None,表示一直等待,直到Thread子线程终止 若Thread子线程是守护线程,超过时间(number)后,退出Thread子线程(不管是否执行完) 若Thread子线程是守护线程且有N(N>=2)个时,则当前线程最多等待(timeout*N),按照调用顺序,第M个Thread子线程在此时间内(等待时间((N-M+1)*timeout))可以执行完则该线程被执行,然后执行下一个线程,等待所有线程执行完或者超时,退出Thread子线程 若Thread子线程不是守护线程,超过时间(number)后,Thread子线程依然可以继续执行,直到所有的Thread子线程执行完 time.sleep(sec) 线程睡眠,主动暂停使线程进入堵塞状态
示例
守护线程时
import threading, time def action(delay): print(threading.current_thread().name+'线程开始\t'+time.asctime()) time.sleep(delay) print(threading.current_thread().name+'线程结束\t'+time.asctime()) print(threading.current_thread().name+'线程开始\t'+time.asctime()) threads = [] #创建线程并指定为守护线程(daemon=True) thread1 = threading.Thread(target=action, args=(5,), name='thread_1', daemon=True) threads.append(thread1) thread2 = threading.Thread(target=action, args=(9,), name='thread_2', daemon=True) threads.append(thread2) ''' 循环子线程列表并调用Thread.join(timeout)方法 主线程此时处于堵塞状态,必须等join(timeout)调用的子线程执行完或超时后,才会被执行 ''' for thread in threads: print(thread.isDaemon()) thread.start() ''' 主线程时最多等待(timeout*线程个数) timeout<2.5时,线程1和2的run()方法的第二个print语句不会被执行; 2.5 <= timeout <= 9,线程1的run()方法的第二个print语句被执行,线程2的run()方法的第二个print语句不会被执行; timeout > 10,线程1和2的run()方法的第二个print语句都会被执行 ''' thread.join(9) print(threading.current_thread().name+'线程结束\t'+time.asctime())
非守护线程时
import threading, time def action1(delay): print(threading.current_thread().name+'线程开始\t'+time.strftime('%H:%M:%S')) time.sleep(delay) print(threading.current_thread().name+'线程结束\t'+time.strftime('%H:%M:%S')) def action2(delay): print(threading.current_thread().name+'线程开始\t'+time.strftime('%H:%M:%S')) time.sleep(delay) print(threading.current_thread().name+'线程结束\t'+time.strftime('%H:%M:%S')) print(threading.current_thread().name+'线程开始\t'+time.strftime('%H:%M:%S')) threads = [] #创建线程并指定为非守护线程 thread1 = threading.Thread(target=action1, args=(5,), name='thread_1') threads.append(thread1) thread2 = threading.Thread(target=action2, args=(9,), name='thread_2') threads.append(thread2) for thread in threads: thread.start() print(thread.isDaemon()) #子线程Daemon=False,不管timeout为任何值,两个子线程都会执行完 thread.join(1) print(threading.current_thread().name+'线程结束\t'+time.strftime('%H:%M:%S'))