当前位置:   article > 正文

Python | threading01 - 创建两个同时运行的子线程_python thread同时开始

python thread同时开始

一、前言


在这里插入图片描述
使用threading库,咱们的python程序就能从单线程串行变成多线程并发。python的threading库实现的“并发”是假的并发,即同一时刻只有一个线程在运行。据说python后来想将这个假的“并发”改为真的并发,但出现特别多的BUG,最后放弃了这个想法。

聊到假的“并行”,学习过单片机(STM32)的嵌入式实时系统RTOS(ucosIII、freeRTOS、RTX5等)的同学就知道,移植了RTOS的单片机,同一时刻仅仅只有一个线程在运行。只是RTOS在很快的切换线程,产生了好像多个线程在同时工作的“假象”。

python多线程与单片机的RTOS在调度规则完全不一样。python多线程的调度程序会在任何时候中断线程(相当于调度,所以python多线程的调度可以说是很难控制的),单片机的RTOS会有相应的API来产生调度(调度是可控的)。

线程与协程之间的比较还有最后一点要说明:如果使用线程做过重要的编程,就知道写出程序有多么困难,因为调度程序任何时候都可能中断线程。必须记住保留锁,去保护程序中的重要部分,防止多步操作在执行的过程中被中断,防止数据处于无效状态。 —《流畅的Python》- Luciano Ramalho

所以,在我看来:python的协程与单片机的RTOS才是相似的。

二、创建两个同时运行的线程


2.1、代码

# 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
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

2.2、运行

从下图可以看到,线程1与线程2都是每隔约1秒时间运行一次。线程1与线程2哪个先运行取决于系统的调度。
在这里插入图片描述

三、threading库的函数


3.1、threading.Thread()

在这里插入图片描述
入口参数:

  • group - 暂时不使用
  • target - 用于执行线程需要执行的线程函数
  • name - 可以自定义线程的名字,不设置的话,系统就自动分配
  • args - 创建线程时,可以给线程函数传递参数
  • kwargs - 暂时不使用
  • daemon - 设置线程是否为守护线程(后台线程)

当我们不对入口参数name赋值的话,系统会自动分配线程名字。
在这里插入图片描述
运行代码:
在这里插入图片描述
接着,我尝试对入口参数name进行赋值。
在这里插入图片描述
运行代码:
在这里插入图片描述
另外一个重要的入口参数是daemon,它的作用是设置线程是否为守护线程(后台线程)。守护线程有一个重要的特点是主线程(例子的main()线程)退出时,守护线程不管怎样都要跟主线程一起退出。
守护线程的目的与作用:
在这里插入图片描述
所以,我的理解是:当创建的子线程是无限循环的话,就应该设置为守护线程。随着主线程的退出,子线程被强制退出,保证了整个python程序正常地,完整地退出。
在这里插入图片描述
运行结果:
main()线程退出,线程t1与t2也跟着退出了。有什么办法解决这个问题?
在这里插入图片描述

3.2、threading.join()

join()方法可以让主线程进入阻塞态,等待其他线程运行结束,接着才解除阻塞态。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.3、threading.start()

start()方法用于启动线程的运行,否则线程不会跑起来。
在这里插入图片描述

四、最终的完整代码


  1. 使用守护线程,主线程退出时,强制让所有的子线程退出,确保整个python程序正常地退出。
  2. 使用threading.join()方法,让主线程等子线程结束,无限循环的子线程可以持续无限执行。
# 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()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/143589
推荐阅读
相关标签
  

闽ICP备14008679号