先简单介绍一下线程的概念:
线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。在Unix System V及SunOS中也被称为轻量进程(lightweight processes),但轻量进程更多指内核线程(kernel thread),而把用户线程(user thread)称为线程。
说白了就是线程就是完成某个特定功能的一段代码,但线程的开销要比进程小的多。一个Python程序至少有一个线程,那就是Python的主线程,程序启动后由Python解释器负责创建主线程,程序结束时由Python解释器来负责结束主线程。
1.简单介绍threading模块的常用函数:
threading.active_count()#返回当前处于活动状态的线程个数
threading.current_thread()#返回当前的Thread对象
threading.main_thread()#返回主线程对象,主线程是Python解释器启动的线程
threading.currentThread()#返回当前的线程变量。
threading.enumerate()#返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
threading.activeCount()#返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。
代码示例:
import threading
#当前处于活动状态的线程的个数
print(threading.active_count())
#当前线程的名字
print(threading.current_thread().name)
#主线程的名字
print(threading.main_thread().name)
#当前的线程变量
print(threading.currentThread())
#一个包含正在运行的线程的list
print(threading.enumerate())
运行结果:
1
MainThread
MainThread
<_MainThread(MainThread, started 140737184076736)>
[<_MainThread(MainThread, started 140737184076736)>]
结果看出,当前线程为Python的主线程,名字为MainThread
2.创建线程
- 创建一个可执行的线程需要线程对象和线程体
- 线程对象:threading模块线程类Thread所创建的对象
- 线程体:线程的执行函数,线程启动会执行该函数,线程所处理的代码是在线程体中编写的
创建线程对象:
class Thread(_Verbose)
__init__(self, group=None, target=None, name=None, args=(), kwargs=None, verbose=None)
*group *:group参数必须为空,参数group是预留的,用于将来扩展;
参数args和kwargs分别表示调用target时的参数列表和关键字参数。
*target *: 参数target是一个可调用对象(也称为活动[activity]),在线程启动后执行
*name *: 参数name是线程的名字。默认值为“Thread - N“,N是一个数字。
*args *:传递给线程函数target的参数, 他必须是个tuple类型.
*kwargs *:kwargs表示关键字参数。字典类型
创建线程体的方法1:自定义函数为线程体
import threading
import time
#自定义线程函数
#线程方法
def threading_body():
#当前对象线程
t = threading.current_thread()
for i in range(1,6):
#当前线程名
print("第{0}次执行线程 {1}".format(i,t.name))
#线程休眠
time.sleep(1)
print("线程{0}执行完成".format(t.name))
def main():
#创建线程t1对象
t1 = threading.Thread(target=threading_body,name='线程1')
#启动线程1
t1.start()
# 创建线程t2对象
t2 = threading.Thread(target=threading_body,name='线程2')
#启动线程2
t2.start()
if __name__ == '__main__':
main()
执行结果:
第1次执行线程 线程1
第1次执行线程 线程2
第2次执行线程 线程1
第2次执行线程 线程2
第3次执行线程 线程1
第3次执行线程 线程2
第4次执行线程 线程1
第4次执行线程 线程2
第5次执行线程 线程1
第5次执行线程 线程2
线程线程1执行完成
线程线程2执行完成
若没有进行线程休眠,执行结果如下:
第1次执行线程 线程1
第2次执行线程 线程1
第3次执行线程 线程1
第4次执行线程 线程1
第5次执行线程 线程1
线程线程1执行完成
第1次执行线程 线程2
第2次执行线程 线程2
第3次执行线程 线程2
第4次执行线程 线程2
第5次执行线程 线程2
线程线程2执行完成
- 由此可见线程休眠是多么的重要,线程执行时交替执行并没有一定的执行顺序。
- 两个线程都循环了5次,线程1和线程2他们运行同一个函数,因此可以通过线程抢夺的性质和线程休眠来实现。
- 使用time.sleep()是为了让两个线程运行的顺序成为(以i为代表)1,1,2,2,3,3,4,4,5,5。当线程1或线程2抢到线程时,执行函数,执行到sleep(),这个线程就会休眠,这时就剩另外一个线程来运行,另一个线程执行完同样休眠。一个线程运行一次就休眠,让给其他没运行过的线程让他们来运行,从而使他们可以几个线程一循环,在一定程序上会阻碍该线程获得 CPU 调度。。
创建线程体的方法2:继承重写run()方法,run()方法作为线程
import threading
import time
class MyThread(threading.Thread):# 继承父类threading.Thread
def __init__(self, name):
# 重写threading.Thread初始化内容
# threading.Thread.__init__(self)
# threading.Thread.__init__(self) = super().__init__()
super().__init__()
self.name = name
# 把要执行的代码写到run函数里面,线程在创建后会直接运行run函数
def run(self):
for i in range(1, 6):
print("第%s次执行线程%s,当前线程%s" % (i, self.name, threading.current_thread().name))
# 线程休眠
time.sleep(1)
print("{0}执行完成".format(self.name))
def main():
# 创建线程对象1
t1 = MyThread("线程1")
# 启动线程1
t1.start()
# 创建线程2
t2 = MyThread("线程2")
# 启动线程2
t2.start()
if __name__ == '__main__':
main()
后台执行结果:
第1次执行线程线程1,当前线程线程1
第1次执行线程线程2,当前线程线程2
第2次执行线程线程1,当前线程线程1
第2次执行线程线程2,当前线程线程2
第3次执行线程线程1,当前线程线程1
第3次执行线程线程2,当前线程线程2
第4次执行线程线程1,当前线程线程1
第4次执行线程线程2,当前线程线程2
第5次执行线程线程1,当前线程线程1
第5次执行线程线程2,当前线程线程2
线程1执行完成
线程2执行完成
- start()方法调用run()方法,而run()方法调用函数
- start()方法是每个线程对象必需至多调用一次,当超过1次的多次调用时,则会抛出错误;在一个单独的线程控制中,它将会调用run()方法
- run()方法可以在子类中重定义。标准run()方法调用回调对象作为参数传递给目标对象的构造函数。
3.线程管理
#线程管理
‘’’
等待线程结束
当前线程调用t1线程的join()方法时则阻塞当前线程,等待t1线程的结束,如果t1线程结束或等待超时,则当前线程回到活动状态继续执行
import threading
import time
class MyThread(threading.Thread):
def __init__(self, name):
# 继承父类
# threading.Thread.__init__(self)
# threading.Thread.__init__(self) = super().__init__()
super().__init__()
self.name = name
# 继承重写run()方法:
def run(self):
for i in range(3):
print("第%s次执行线程%s,当前线程%s" % (i, self.name, threading.current_thread().name))
# 线程休眠
time.sleep(1)
print("{0}执行完成".format(self.name))
def main():
print("主线程%s开始" % (threading.current_thread().name))
# 创建线程
t1 = MyThread("线程1")
t2 = MyThread("线程2")
# 启动线程
t1.start()
t2.start()
# 阻塞主线程,等子线程结束
t1.join()
t2.join()
print("主线程%s结束" % (threading.current_thread().name))
if __name__ == '__main__':
main()
后台执行结果:
主线程MainThread开始
第0次执行线程线程1,当前线程线程1
第0次执行线程线程2,当前线程线程2
第1次执行线程线程1,当前线程线程1
第1次执行线程线程2,当前线程线程2
第2次执行线程线程1,当前线程线程1
第2次执行线程线程2,当前线程线程2
线程2执行完成线程1执行完成
主线程MainThread结束
怎么证明主线程让阻塞了呢,可以将t1.join()这行代码注释掉,执行结果如下:
主线程MainThread开始
第0次执行线程线程1,当前线程线程1
第0次执行线程线程2,当前线程线程2
主线程MainThread结束
第1次执行线程线程1,当前线程线程1
第1次执行线程线程2,当前线程线程2
第2次执行线程线程1,当前线程线程1
第2次执行线程线程2,当前线程线程2
线程2执行完成
线程1执行完成