赞
踩
使用threading库,咱们的python程序就能从单线程串行变成多线程并发。python的threading库实现的“并发”是假的并发,即同一时刻只有一个线程在运行。据说python后来想将这个假的“并发”改为真的并发,但出现特别多的BUG,最后放弃了这个想法。
聊到假的“并行”,学习过单片机(STM32)的嵌入式实时系统RTOS(ucosIII、freeRTOS、RTX5等)的同学就知道,移植了RTOS的单片机,同一时刻仅仅只有一个线程在运行。只是RTOS在很快的切换线程,产生了好像多个线程在同时工作的“假象”。
python多线程与单片机的RTOS在调度规则完全不一样。python多线程的调度程序会在任何时候中断线程(相当于调度,所以python多线程的调度可以说是很难控制的),单片机的RTOS会有相应的API来产生调度(调度是可控的)。
线程与协程之间的比较还有最后一点要说明:如果使用线程做过重要的编程,就知道写出程序有多么困难,因为调度程序任何时候都可能中断线程。必须记住保留锁,去保护程序中的重要部分,防止多步操作在执行的过程中被中断,防止数据处于无效状态。 —《流畅的Python》- Luciano Ramalho
所以,在我看来:python的协程与单片机的RTOS才是相似的。
# python3.9 import time import threading def thread1(): """ 线程1 """ while True: # 打印信息,并打印性能计数器的值 print("I am thread1,time is %f" % time.perf_counter()) time.sleep(1) # 休眠1秒 def thread2(): """ 线程2 """ while True: # 打印信息,并打印性能计数器的值 print("I am thread2,time is %f" % time.perf_counter()) time.sleep(1) # 休眠1秒 def main(): """ 主线程 """ t1 = threading.Thread(target=thread1) # 创建thread1线程 t2 = threading.Thread(target=thread2) # 创建thread2线程 t1.start() # 启动thread1线程 t2.start() # 启动thread2线程 if __name__ == "__main__": main()
从下图可以看到,线程1与线程2都是每隔约1秒时间运行一次。线程1与线程2哪个先运行取决于系统的调度。
入口参数:
当我们不对入口参数name赋值的话,系统会自动分配线程名字。
运行代码:
接着,我尝试对入口参数name进行赋值。
运行代码:
另外一个重要的入口参数是daemon,它的作用是设置线程是否为守护线程(后台线程)。守护线程有一个重要的特点是主线程(例子的main()线程)退出时,守护线程不管怎样都要跟主线程一起退出。
守护线程的目的与作用:
所以,我的理解是:当创建的子线程是无限循环的话,就应该设置为守护线程。随着主线程的退出,子线程被强制退出,保证了整个python程序正常地,完整地退出。
运行结果:
main()线程退出,线程t1与t2也跟着退出了。有什么办法解决这个问题?
join()方法可以让主线程进入阻塞态,等待其他线程运行结束,接着才解除阻塞态。
start()方法用于启动线程的运行,否则线程不会跑起来。
# python3.9 import time import threading def thread1(): """ 线程1 """ while True: # 打印信息,并打印性能计数器的值 print("I am thread1,time is %f" % time.perf_counter()) time.sleep(1) # 休眠1秒 def thread2(): """ 线程2 """ while True: # 打印信息,并打印性能计数器的值 print("I am thread2,time is %f" % time.perf_counter()) time.sleep(1) # 休眠1秒 def main(): """ 主线程 """ t1 = threading.Thread(target=thread1,name="fun_thread1",daemon=True) # 创建thread1线程 t2 = threading.Thread(target=thread2,name="fun_thread2",daemon=True) # 创建thread2线程 t1.start() # 启动thread1线程 t2.start() # 启动thread2线程 print("t1的线程名字是 %s" % t1.getName()) # 打印t1线程的线程名字 print("t2的线程名字是 %s" % t2.getName()) # 打印t2线程的线程名字 t1.join() # 当前需要等待线程t1执行完毕后才能运行下一步 t2.join() # 当前需要等待线程t2执行完毕后才能运行下一步 print("主线程执行完毕!") if __name__ == "__main__": main()
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。