进程的缺陷:
- 进程只能在一个时间干一件事,如果想同时干两件事或多件事,进程就无能为力了。
- 进程在执行的过程中如果阻塞,例如等待输入,整个进程就会挂起,即使进程中有些工作不依赖于输入的数据,也将无法执行。
- 进程的创建和销毁都需要较大的消耗
为了处理进程的这些缺陷,后面开始引入线程的概念,线程可以理解为进程中的执行单元,每个进程至少有一个线程,好比车间里的工人。一个大的任务拆解成小任务给线程完全,比如聊天软件进程,监听输入给线程1执行,发送内容给线程2执行,接收回应给线程3执行。线程之间不会相互阻塞。如果使用进程来负责这几个小任务,除了会造成资源消耗较大,还需要处理进程间的通信,都是费时费力。
线程的特点
1)轻型实体,线程中的实体基本上不拥有系统资源,只是有一点必不可少的、能保证独立运行的资源。
2)最小的独立调度和分派的基本单位,线程的切换非常迅速且开销小
3)一个进程下的几个线程共享该进程的资源和数据
4)在一个进程中的多个线程之间,可以并发执行
线程模块
在python中对于线程的使用,建议使用threading模块,它提供了比thread模块更高级别、功能更强的线程管理的功能;
Queue模块允许用户创建一个可以用于多个线程之间共享数据的队列数据结构。
Thread类的使用
Thread类是用于创建线程,其初始化__init__方法如下
def __init__(self, group=None, target=None, name=None,
args=(), kwargs=None, *, daemon=None):
参数名 | 作用 |
---|---|
target | 使用函数名指定此线程执行的代码 |
name | 用字符串为此线程实例命名 |
args | 以元组的形式,为线程调用的函数传递位置参数;如果单个参数逗号结尾(a,) |
kwargs | 以字典的形式,为线程调用的函数传递关键字参数 |
线程启动与退出
import threading
import time
def func():
while True:
print('I working...')
time.sleep(1)
print('fineshed')
t=threading.Thread(target=func,name='test1')#依据类完成一个线程对象的创建
t.start()#线程的启动,需要调用线程对象的方法start()
线程的符合以下情况时会完成退出:
- 线程执行的代码完毕
- 线程执行代码过程中抛出异常
而我们的写的线程实例t进入循环执行,故也不会退出。
对线程传参
import threading
def add(x,y):
print('{}+{}={}'.format(x,y,x+y))
t1=threading.Thread(target=add,args=(4,5))
#t1=threading.Thread(target=add,kwargs={'x':4,'y':5})
#t1=threading.Thread(target=add,args=(4,),kwargs={'y':5})
t1.start()
threading模块中的函数
函数名 | 作用 |
---|---|
current_thread | 返回当前线程对象 |
main_thread | 返回当前主线程对象 |
active_count | 返回当前进程中活动的线程数量 |
get_ident | 返回当前线程的ID |
import threading
import time
def showthreadinfo():
print('currentthread={}'.format(threading.current_thread()))
print('main thread={}'.format(threading.main_thread()))
print('active thread={}'.format(threading.active_count()))
print('current thread ID={}'.format(threading.get_ident()))
t=threading.Thread(target=showthreadinfo,name='test03')
showthreadinfo()#先主线程中执行showthreadinfo函数
t.start()#在子线程中执行showthreadinfo函数,比较两者返回的结果
Thread类的中的属性和方法
名称 | 含义 |
---|---|
name | 表示此线程实例的名字 |
ident | 表示此线程实例的ID,只有线程启动的实现才被分配线程ID号。未启动时返回none |
is_alive() | 此方法判定线程实例是否存活,返回True表示活动,False表示未活动 |
import threading
import time
def func1():
count=0
while True:
if count>5:
break
time.sleep(1)
count+=1
t=threading.Thread(target=func1,name='test4')
print(t.ident)
t.start()
print(t.ident)
while True:
time.sleep(1)
if t.is_alive():
print('{} {} is alive'.format(t.name,t.ident))
名称 | 含义 |
---|---|
start() | 启动线程实例并在线程实例中开始执行代码 |
run() | 在当前线程中执行代码 |
start()和run()的区别
- start()在执行过程中,会调用run()方法;
- start()是先启动一个线程,然后在此线程中执行run();而run()则不会启动新的线程,直接以主线执行代码。
分别使用start()和run()验证。
import threading
import time
def func1():
time.sleep(1)
print('working')
print(threading.current_thread().name)
class MyThread(threading.Thread):
def start(self):
print('start-----')
super().start()
def run(self):
print('run-----')
super().run()
t=MyThread(target=func1,name='test4')
t.start()
#t.run()
守护线程
名称 | 含义 |
---|---|
daemon | 只有两个值True或False,默认为False,表示为非守护线程 |
isdaemon() | 返回线程的daemon属性值 |
进程的主线程daemon属性值默认为False;
- 假如进程中存在还活动的线程a且线程a的daemon属性也为False,即存在活动的非守护线程,则主线程会等待线程a结束。
- 假如daemon属性为false的线程已经结束,当前活动线程b的属性为True,则主线程不会等待,直接结束并杀掉线程b。如果仍希望主线程等待需要设置线程b.join()