博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
python3之线程(一)
阅读量:4622 次
发布时间:2019-06-09

本文共 3788 字,大约阅读时间需要 12 分钟。

线程的概念

现在的操作系统几乎都支持运行多个任务,而在操作系统内部,一个任务往往代表的执行的某一个程序,也就是运行中的程序,运行的程序是一个动态的概念,也就是所说的进程,而在进程内部,往往有许多顺序执行流,这些顺序执行流就是线程。

线程的创建

Python提供了 _thread 和 threading 两个模块来支持多线程,其中 _thread 提供低级别的、原始的线程支持,以及一个简单的锁,正如它的名字所暗示的,一般编程不建议使用 thread 模块;而 threading 模块则提供了功能丰富的多线程支持。

Python 主要通过两种方式来创建线程:

  1. 使用 threading 模块的 Thread 类的构造器创建线程。
  2. 继承 threading 模块的 Thread 类创建线程类。

使用Thread类创建线程

Thread类的构造或者说初始化的__init__方法如下:

__init__(self, group=None, target=None, name=None, args=(), kwargs=None, *,daemon=None)

上面的构造器涉及如下几个参数:

  • group:指定该线程所属的线程组。目前该参数还未实现,因此它只能设为 None。
  • target:指定该线程要调度的目标方法。
  • args:指定一个元组,以位置参数的形式为 target 指定的函数传入参数。元组的第一个元素传给 target 函数的第一个参数,元组的第二个元素传给 target 函数的第二个参数……依此类推。
  • kwargs:指定一个字典,以关键字参数的形式为 target 指定的函数传入参数。
  • daemon:指定所构建的线程是否为后代线程。

通过 Thread 类的构造器创建井启动多线程的步骤如下:

  1. 调用 Thread 类的构造器创建线程对象。在创建线程对象时,target 参数指定的函数将作为线程执行体。
  2. 调用线程对象的 start() 方法启动该线程。

示例:

import  threading#定义一个函数,该函数返回当前执行的进程名字def fc(value):    for i in range(value):     # 调用threading模块current_thread()函数获取当前线程     # 线程对象的getName()方法获取当前线程的名字         print(threading.current_thread().getName() + "--->" + str(i))  #定义线程执行体for i in range(10):    print(threading.current_thread().getName() + '--->' + str(i))    if i == 5:    #当if条件成立时,执行子线程        sd = threading.Thread(target=fc, args=(10, ))        sd.start()print("主线程执行完毕")

程序可以通过 setName(name) 方法为线程设置名字,也可以通过 geName() 方法返回指定线程的名字,这两个方法可通过 name 属性来代替。在默认情况下,主线程的名字为 MainThread,用户启动的多个线程的名字依次为 Thread-1、Thread-2、Thread-3、...、Thread-n 等。

继承 threading 模块的 Thread 类创建线程类

通过继承 Thread 类来创建并启动线程的步骤如下:

  1. 定义 Thread 类的子类,并重写该类的 run() 方法。run() 方法的方法体就代表了线程需要完成的任务,因此把 run() 方法称为线程执行体。
  2. 创建 Thread 子类的实例,即创建线程对象。
  3. 调用线程对象的 start() 方法来启动线程。

示例:

import  threadingclass DefineThread(threading.Thread):    def __init__(self):        #调用父类的初始化方法。        threading.Thread.__init__(self) #或者        #super().__init__()        self.i = 0      #重新定义run方法,也就是线程的执行体    def run(self):        while self.i < 5:            print(threading.current_thread().name  + "--->" + str(self.i))            self.i += 1#主程序for i in range(10):    print(threading.current_thread().name + '--->' + str(i))    if i == 5:        dt = DefineThread()        dt.start()print("主线程执行完毕")

 方法

join方法

Thread 提供了让一个线程等待另一个线程完成的 join() 方法。当调用程序调用另外一个线程的join()方法时,需要等待另外一个线程执行完成才继续执行当前的程序。也就是说当前的执行程序会被阻塞。

示例:

import  threadingdef ft(value):    for i in range(value):        print(threading.current_thread().name + "--->" +str(i))#主程序for i in range(5):    if i == 2:        dt = threading.Thread(target=ft, args=(5, ), name = "被其他线程调用join()方法的线程")        dt.start()        dt.join()    print(threading.current_thread().name + "--->" + str(i))print("主线程执行完毕")

输出如下:

MainThread--->0MainThread--->1被其他线程调用join()方法的线程--->0被其他线程调用join()方法的线程--->1被其他线程调用join()方法的线程--->2被其他线程调用join()方法的线程--->3被其他线程调用join()方法的线程--->4MainThread--->2MainThread--->3MainThread--->4主线程执行完毕

可以看出,当子线程在执行的时候,主线程是被阻塞的。

daemon(守护或者后台进程)

daemon属性用来设置线程运行在后台,默认是运行在前台。当所有的前台进程都死掉时,后台进程也结束,不管后台进程是否运行完毕。

示例

import  threadingdef ft(value):    for i in range(value):        print(threading.current_thread().name + "--->" +str(i))t  = threading.Thread(target=ft, args=(100, ), name = "后台线程", daemon=True)t.start()#如果没有在创建线程对象指定daemon=True,那么也可以通过下面的属性设置#t  = threading.Thread(target=ft, args=(100, ), name = "后台线程")#t.daemon = True#主程序for i in range(5):    print(threading.current_thread().name + "--->" + str(i))print("主线程执行完毕")

上述程序在执行的时候,正常应该是t这个线程对象执行到99的时候才推出,但是,在主程序内部的线程执行完毕(也就是前台进程完毕),那么后台进程也会随之退出。

从上面的程序可以看出,主线程默认是前台线程,t线程默认也是前台线程。但并不是所有的线程默认都是前台线程,有些线程默认就是后台线程。前台线程创建的子线程默认是前台线程,后台线程创建的子线程默认是后台线程。

可见,创建后台线程有两种方式:

  1. 主动将线程的 daemon 属性设置为 True。
  2. 后台线程启动的线程默认是后台线程。

注意,当前台线程死亡后,Python 解释器会通知后台线程死亡,但是从它接收指令到做出响应需要一定的时间。如果要将某个线程设置为后台线程,则必须在该线程启动之前进行设置。也就是说,将 daemon 属性设为 True,必须在 start() 方法调用之前进行,否则会引发 RuntimeError 异常。

转载于:https://www.cnblogs.com/yjt1993/p/11117030.html

你可能感兴趣的文章
MySql【Error笔记】
查看>>
vue入门
查看>>
JS线程Web worker
查看>>
Flex的动画效果与变换!(三)(完)
查看>>
mysql常见错误码
查看>>
Openresty 与 Tengine
查看>>
使用XV-11激光雷达做hector_slam
查看>>
布局技巧4:使用ViewStub
查看>>
学习记事
查看>>
java 子类重写父类的方法应注意的问题
查看>>
[LevelDB] LevelDB理论基础
查看>>
【codecombat】 试玩全攻略 第一关kithguard地牢
查看>>
【DP】 POJ 1191 棋盘分割 记忆化搜索
查看>>
自动化测试 Appium之Python运行环境搭建 Part2
查看>>
说说DBA职责和目标
查看>>
从头认识Spring-2.4 基于java的标准注解装配-@Inject-限定器@Named
查看>>
sql server 实现多表连接查询
查看>>
Python标准库:内置函数getattr(object, name[, default])
查看>>
转:android 自定义RadioButton样式
查看>>
HTTP请求过程
查看>>