线程
线程
1、什么是线程
进程:资源单位
线程:执行单位
线程与进程都是虚拟的概念,为了更好的表达某种事物
注意:开启一个进程,一定会自带一个线程,线程才是真正的执行者
2、为什么要使用线程
节省资源的占用
开启进程:
1、产生一个内存空间,申请一块资源
2、会自带一个主线程
3、开启子进程的速度要比开启子线程的速度慢
开启线程:
1、一个进程内可以开启多个线程,从进程的内存空间中申请执行单位
2、节省资源
开启几个进程就会开辟几个内存空间,开辟几个线程是在同一个内存空间中申请几个执行单位
3、使用线程
同进程的使用相似,调用的是Thread生成对象obj,通过obj.start()开启线程
from threading import Thread
import time
# 方式1:直接调用
num = 100
def task():
global num
num = 200
print('开启子线程')
time.sleep(1)
print('子线程结束')
if __name__ == '__main__':
t = Thread(target=task)
t.start()
print('主进程(主线程)结束') # 子线程要比子进程开启快
# 开启子线程
# 主进程(主线程)结束
# 子线程结束
from threading import Thread
import time
num = 10
# 方式2:定义类,并重写run方法
class Mythread(Thread):
# 重写run方法
def run(self):
print('开启子线程')
time.sleep(1)
print('子线程结束')
if __name__ == '__main__':
t = Mythread()
# 创建子线程
t.start()
# 让子线程结束后主进程才结束
t.join()
print('主进程(主线程)结束')
# 开启子线程
# 子线程结束
# 主进程(主线程)结束
4、守护线程
当主线程结束后,子线程也立即结束,并回收,通过 obj.daemon = True 定义在obj.start() 之前设置
from threading import Thread
# 当前线程
from threading import current_thread
import time
num = 10
def task():
global num
num = 20
print('开启子线程')
time.sleep(1)
print('子线程结束')
if __name__ == '__main__':
t = Thread(target=task)
t.daemon = True
t.start()
# current_thread().name查看当前线程名
print(f'主进程(主线程)结束{current_thread().name}')
# 开启子线程
# 主进程(主线程)结束MainThread
5、线程互斥锁
互斥锁是用来保证数据读写安全的,在修改同一个数据时,同一时间只能有一个任务可以进行修改,即串行的修改,保证数据安全
from threading import Thread
from threading import Lock
import time
lock = Lock()
num = 10
def task():
global num
lock.acquire()
time.sleep(1)
num += 1
lock.release()
if __name__ == '__main__':
list1 = []
for i in range(10):
t = Thread(target=task)
t.start()
list1.append(t)
for t in list1:
t.join()
print(num) # 20
6、线程池
每一个线程的从生成到消亡也是需要时间和资源的,太多的线程会占用过多的系统资源(内存开销,cpu开销),而且生成太多的线程也是需要时间的,很可能会得不偿失 ,线程池是用来限制每次线程的数量
from concurrent.futures import ThreadPoolExecutor
import time
# 每次线程的数量为10
pool = ThreadPoolExecutor(10)
def task(line):
print(line)
time.sleep(5)
if __name__ == '__main__':
for line in range(100):
pool.submit(task, line)