(8)什么是线程(如何开启线程)以及线程的其他属性

为什么会出现线程

进程的缺点:

1、非常消耗资源,计算机不能无限开启子进程

2、如果开了过多的进程,cpu的切换进程的模式下是非常耗时的

因为进程的缺点,线程的出现就是为了解决进程的缺点,线程的开销小于进程

1、所以线程就是轻量级的进程

2、一个进程里面至少有一个线程

3、线程就是具体干活的,执行任务的

PS:进程相当于一座工厂,线程相当于干活的人

PS:进程是一个资源的实体单位,而cpu操作的最小单位是线程

理论案例:

QQ是一个主进程

QQ内有几个功能

1、聊天

2、支付

3、视频

PS:如果没有线程,就要开3个进程,这样计算机的消耗就会变大

PS:线程的启动速度要高于进程的速度

开启QQ主进程后,下面所有的功能就交给线程去执行,这样既对计算机的资源消耗低了,而且速度也快了

线程的好处

1、线程的开启速度快于进程

2、一个进程下的线程和线程之间是共享进程的资源

3、cpu在线程之间的切换速度远快于进程

PS:同一个进程下的数据在线程之间是共享的

线程和进程使用的场景

线程的使用场景:有大量IO存在的时候,使用线程  # IO就是一个读写的过程,包括网络请求

进程的使用场景:有密集计算的时候使用进程  

开启线程的方式有两种

1、函数的方式

import time
from threading import Thread # 从threading 包导入Thread模块,Thread模块就是开启子线程的

def task(arg):
print("%s is running..."% arg)
time.sleep(1) #这个模拟IO
print("%s is done..."% arg)

if __name__ == '__main__':
t = Thread(target=task,args=('子线程,')) #这是开启子线程,子线程肯定是在主线程里面开启
t.start() #子线程在开启的瞬间就执行了
print('主线程') #这里为什么是主线程,因为运行整段程序的时候是需要开一个进程,进程里面就有线程

PS:子线程的开启代码写法和主线程基本一样
PS:子线程要快于主线程
PS:开启子线程后,下面运行的肯定是主线程,而开启子进程后面运行的肯定是主进程

2、类的方式

from threading import Thread

class MyThread(Thread): #继承包中的开启子进程模块
def run(self): #重新定义模块下的run函数
print("hell0")

if __name__ == '__main__':
t = MyThread()
t.start()
print('主线程')

 

线程和进程速度对比实例

import time
from multiprocessing import Process
from threading import Thread

def task(arg):
print("%s is running..."%arg)
time.sleep(1) #这个模拟IO
print("%s is done..." %arg)


if __name__ == '__main__':
t = Thread(target=task,args=('子线程',))
p = Process(target=task,args=('子进程',))
t.start()
p.start()
print('主线程')

PS:子线程先开启,然后主线程,子进程要等很久才开启,由于子进程开启需要向操作系统申请内存空间,在申请资源,所以进程的速度慢于线程

同一个进程下开启线程共享数据

from threading import Thread

x = 100

def task():
global x # x定义成全局
x = 0

if __name__ == '__main__':
t = Thread(target=task)
t.start() #开启一个线程
print(x)
PS:可以看到线程下的程序运行时候把x的值已经修改了,说明线程下的数据是共享的,而在进程下是无法修改的,所以进程的数据是不共享的

线程的其他属性

1、p.pid() :  #获取进程id
2、os.getpid() :  #获取进程id
3、os.getppid() :  #获取父进程id
4、p.name:  #进程的名称
5、p.daemon: #默认值为False,如果设为True,代表p为后台运行的守护进程,当p的父进程终止时,p也随之终止,并且设定为True后,p不能创建自己的新进程,必须在p.start()之前设置
6、p.is_alive():  #如果p仍然运行,返回True
7、current_thread() #这是一个类,代表当前的线程,这个类下有很多方法,比如current_thread().name代当前线程的名称,也可以用t.name来获取当前线程的名称
 8、active_count() #这是一个类,查看当前线程活跃数

1、t.is_alive() # 查看线程是否存活

from threading import Thread

def task():
print('xxxxxxxxx')

if __name__ == '__main__':
t = Thread(target=task)
t.start()
print(t.is_alive()) #查看线程是否存活,存活就是True,死了就是False
print('主')

2、t.join() # 等待子线程执行完毕

例1:
from threading import Thread

def task():
print('xxxxxxxxx')

if __name__ == '__main__':
t = Thread(target=task)
t.start()
t.join() #等待子线程执行完毕
print(t.is_alive())
print('主')
PS:由于子线程开启是异步的,所以如果用join等待子线程执行完毕再查看线程是否存活,肯定是False
例:2
import time
from threading import Thread

def task():
print('xxxxxxxxx')
time.sleep(1) #这个模拟IO

if __name__ == '__main__':
start = time.time()
t_l = []
for i in range(10):
t = Thread(target=task)
t_l.append(t) # 将线程放入列表
t.start()
for t in t_l:
t.join() #等待每个线程结束
end = time.time()
print(end-start)
PS:利用for循环一次开启10个线程,然后用join方法等待线程执行完毕,计算所有线程执行的时间,由于线程之间是异步的,所以同时开了10个线程,10个线程同时睡了1秒,所以结果开启线程到线程结束只用了一秒

current_thread类下方法使用(.name查看当前线程名) 

from threading import Thread,current_thread #必须从threading包下倒入current_thread类

def task():
print('xxxxxxxxx')
print(current_thread().name) #这里就是用类current_thread().name查看当前线程名

if __name__ == '__main__':
t = Thread(target=task,name='QQ')
t.start()
print('主')

active_count方法查看当前活跃的线程数

from threading import Thread,active_count #从threading包下倒入active_count方法

def task():
print('xxxxxxxxx')

if __name__ == '__main__':
t = Thread(target=task,name='QQ')
t.start()
print(active_count()) #查看当前活跃的线程数
print('主')

守护线程

守护进程:守护的是父进程

守护线程:守护的是进程内的其他线程(比如一个进程内有10个线程,有一个是守护线程,这个守护线程要等另外的9个线程执行完毕才会死),守护的是整个进程的运行周期

开启守护线程

import time
from threading import Thread,current_thread #current_thread定义守护线程的名字

def task():
print('%s is running...'%current_thread().name) # 打印守护线程的名字
time.sleep(1) #这个模拟IO
print('%s is done...' % current_thread().name)

if __name__ == '__main__':
t = Thread(target=task,name='守护进程')
t.daemon=True #daemon就是开启守护线程
t.start()
print('主线程')

守护线程实例

from threading import Thread
import time

def foo():
print(123)
time.sleep(3) #这个就是模拟IO
print('end123')

def bar():
print(456)
time.sleep(1) #这个就是模拟IO
print('end456')

t1 = Thread(target=foo)
t2 = Thread(target=bar)
t1.daemon=True
t1.start()
t2.start()
print('main---------')

PS:开启了两个线程t1和t2,t1设置了一个守护线程,t1必须等着t2执行完以及主线程执行完才会死亡,t1.start和t2.start开启线程时候会立马执行函数,t1执行foo函数然后会睡3秒,这时候同时t2执行bat函数然后睡1秒后执行完毕,主线程执行完毕,所以t1子线程里面最后一个不会执行,因为主线程已经执行完毕,守护进程直接死亡,t1这个子线程结束

原文地址:https://www.cnblogs.com/shizhengquan/p/10262453.html