线程基本理论
"""
1.线程是:
一条流水线的工作流程
进程:在内存中开启一个进程空间,将主进程的所有的资源数据复制一份,然后调用cpu去执行
具体描述:
在内存中开启一个进程空间,将主进程的所有的资源数据复制一份,然后调用线程去执行代码
***进程是资源单位,用于划分空间
***线程是执行单位,用于执行,线程是CPU中最小的执行单位
开启一个进程的过程:
进程会在内存中开辟一个进程空间,将主进程的资数据全部复制一份,线程会执行里面的代码
2.线程vs进程
1.开启进程的开销大,比开启线程的开销大很多
2.开启线程的速度非常快,快到几十倍到上百倍
3.线程与线程之间可以共享数据,进程与进程之间需要借助队列等方法实现通信
进程内部的数据是共享的,进程里面的所有线程
进程与进程之间是有隔离的,利用queue队列可以通信
总结:
线程:开销小,执行速度快,同一个进程下的线程资源内存级别可共享
进程:开销大,执行速度慢,不同进程下的数据内存级别不共享,只能通过队列通信
3.线程的应用:
并发:一个cpu看起来像是同时执行多个进程
单个进程下开启是哪个线程:
开启三个进程并发的执行任务
一般使用多线程进行开发
使用进程还是使用线程:
一个软件:例如文件编辑器
1.输入文字
2.在屏幕中显示
3.保存在磁盘中
这个时候开启多线程就会非常好用了,优点:
数据可以共享,开销小,速度快
4.主线程和子线程的关系:
主线程和子线程没有地位之分,但是一个进程,最少需要一个主线程执行任务,当执行完成,
主线程需要等待其他子进程执行完成,才能结束本线程
"""
线程相关方法
开启线程的两种方式
# 第一种方式 函数方法
from threading import Thread
import time
def task(name):
print(f'{name} is running')
time.sleep(1)
print(f'{name} is gone')
# 线程可以不再main下面写,便于理解还是写上吧
if __name__ =='__main__':
t1 = Thread(target=task,args=('zs',)) # 涉及到代码都是主线程执行
t1.start()
print('==主线程') # 线程是没有主次之分
# 第二种方式 类方法
from threading import Thread
import time
class MyThread(Thread):
def __init__(self,name,l1,ls1):
super().__init__()
self.name = name
self.l1 = l1
self.ls1 = ls1
def run(self):
print(f'{self.name,self.l1,self.ls1} is running')
time.sleep(1)
print(f'{self.name,self.l1,self.ls1} is gone')
if __name__ =='__main__':
t1 = MyThread('zs',[1,2,3],'11')
t1.start()
print('==主进程')
from threading import Thread
from multiprocessing import Process
import time
def task(name):
print(f'{name} is running')
time.sleep(1)
print(f'{name} is gone')
# 线程可以不再main下面写,便于理解还是写上吧
if __name__ =='__main__':
# 在主进程下开启主线程
t1 = Process(target=task,args=('zs',)) # 涉及到代码都是主线程执行
t1.start()
print('==主线程') # 线程是没有主次之分
多线程多进程开启的速度区别
"""
多线程多进程开启的速度区别
开启速度上,线程开启比进程快很多
"""
# 多线程启动速度慢一些
from multiprocessing import Process
import os
import time
def task():
print(f'子进程{os.getpid()} is running')
print(f'子进程{os.getpid()} is gone')
if __name__ == '__main__':
start_time = time.time()
t = Process(target=task)
t.start()
t1 = Process(target=task)
t1.start()
t2 = Process(target=task)
t2.start()
t3 = Process(target=task)
t3.start()
print(f'主进程{os.getppid()}结束') # 进程有主次之分,运行速度比线程慢
print(f'{time.time()-start_time}')
# 输出
# 子进程19516 is running
# 子进程19516 is gone
# 主进程590结束
# 0.009748220443725586
# 子进程19517 is running
# 子进程19517 is gone
# 子进程19518 is running
# 子进程19518 is gone
# 子进程19519 is running
# 子进程19519 is gone
# 多线程执行速度快
from threading import Thread
from threading import activeCount
import time
import os
def task():
print(f'子线程{os.getpid()} is running')
print(f'子线程{os.getpid()} is gone')
if __name__ == '__main__':
start_time = time.time()
t = Thread(target=task)
t.start()
t1 = Thread(target=task)
t1.start()
t2 = Thread(target=task)
t2.start()
t3 = Thread(target=task)
t3.start()
print(f'主线程{os.getpid()}结束') # 线程没有主次之分 几乎同时执行完
print(f'{time.time()-start_time}')
# 输出
# 子线程19533 is running
# 子线程19533 is gone
# 子线程19533 is running
# 子线程19533 is gone
# 子线程19533 is running
# 子线程19533 is gone
# 子线程19533 is running
# 子线程19533 is gone
# 主线程19533结束
# 0.0005669593811035156
线程进程pid
from threading import Thread
import os
def task():
print(f'{os.getpid()}')
print(f'{os.getpid()}')
if __name__ == '__main__':
t = Thread(target=task)
t.start()
t.join()
print(f'{os.getpid()}') # 同一个进程下,线程的pid都是一样的
# 输出
# 19135
# 19135
# 19135
同一进程内线程是共享数据
from threading import Thread
x = 3
def task():
"""
修改全局变量的值
:return:
"""
global x
x = 100
if __name__ == '__main__':
t = Thread(target=task)
t.start()
t.join()
print(f'{x}') # 同一个进程内,线程之间的数据是共享的
# 输出100
线程的其他方法
from threading import Thread
from multiprocessing import Process
from threading import currentThread
from threading import enumerate
from threading import activeCount
import time
import os
x = 3
def task():
global x
x = 100
time.sleep(1)
print(os.getpid())
# 对象的属性
if __name__ =='__main__':
t1 = Thread(target=task) # t1 线程
# name 设置线程名
t1.start()
time.sleep(2)
print(t1.isAlive()) # 判断线程是否活着
# False
print(t1.getName()) # 获取线程名
# Thread-1
t1.setName('zs') # 设置线程名**
print(t1.name)
# zs
print(f'==主线程{x}') # 同一进程内的资源数据对于这个进程的多线程来说是共享的
# 模块的属性
if __name__ =='__main__':
t1 = Thread(target=task,name=('zs')) # 涉及到代码都是主线程执行
t2 = Thread(target=task,name=('zs2')) # 涉及到代码都是主线程执行
t1.start()
t2.start()
print(currentThread()) # 获取当前线程的对象
# <_MainThread(MainThread, started 140736975586240)>
print(enumerate()) # 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
# [<_MainThread(MainThread, started 140736975586240)>, <Thread(zs, started 123145558224896)>, <Thread(zs2, started 123145563480064)>]
print(activeCount()) # ***返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。
# 3
print('==主线程')
join
# join 阻塞 告诉主线程要等待子线程执行完毕再执行主线程
# join 将执行的子线程和主线程变成串行,子线程和子线程之间是并行
# .start().join().start().join().start().join()是串行
# .srart().start().start().join().join().join()是并发
# for i in t t.start() for i in t1 t1.join() 是并发
from threading import Thread
import time
def task(name):
print(f'{name} is running')
time.sleep(1)
print(f'{name} is gone')
if __name__ == '__main__':
start_time = time.time()
t1 = Thread(target=task,args=('海狗1',))
t2 = Thread(target=task,args=('海狗2',))
t3 = Thread(target=task,args=('海狗3',))
# 串行
t1.start()
t1.join()
t2.start()
t2.join()
t3.start()
t3.join()
print(f'===主线程{time.time()-start_time}') # 线程没有主次之分
# 输出
# 海狗1 is running
# 海狗1 is gone
# 海狗2 is running
# 海狗2 is gone
# 海狗3 is running
# 海狗3 is gone
# ===主线程3.0098721981048584
from threading import Thread
import time
def task(name):
print(f'{name} is running')
time.sleep(1)
print(f'{name} is gone')
if __name__ == '__main__':
start_time = time.time()
t1 = Thread(target=task,args=('海狗1',))
t2 = Thread(target=task,args=('海狗2',))
t3 = Thread(target=task,args=('海狗3',))
# 并发
t1.start()
t2.start()
t3.start()
t1.join()
t2.join()
t3.join()
print(f'===主线程{time.time()-start_time}') # 线程没有主次之分
# 输出
# 海狗1 is running
# 海狗2 is running
# 海狗3 is running
# 海狗1 is gone
# 海狗2 is gone
# 海狗3 is gone
#
# ===主线程1.0116689205169678
守护线程
# 守护线程:守护非子线程和主线程
# 什么时候结束:
# 如果守护线程的生命周期小于其他线程,会先结束
# 否则等待其他非守护子进程以及主线程结束之后结束
from threading import Thread
import time
def sayhi(name):
print('你滚!')
time.sleep(2)
print('%s say hello' %name) # 先执行子线程
if __name__ == '__main__':
t = Thread(target=sayhi,args=('egon',))
# t.setDaemon(True) #必须在t.start()之前设置
t.daemon = True
t.start() # 线程的开启速度要比进程快很多
print('主线程') # 最后执行主线程
# 输出
# 你滚!
# 主线程
# 守护子线程睡的短,非子线程睡的久,其他非子线程还没有结束,守护子线程也未结束,继续执行,end123输出,都结束完了,主线程结束
from threading import Thread
import time
def foo():
"""
先执行子线程
:return:
"""
print(123) # 1 先打印123
time.sleep(1) # 子线程睡了,只睡1秒,下面的不执行,开始走t2
print("end123") # 4 接着主进程的输出,再打印end123,继续往下走,走t2
def bar():
"""
再执行子线程
:return:
"""
print(456) # 2 再打印456
time.sleep(3) # 子进程睡了,睡了3秒,下面不执行
print("end456") # 5 接着t1的输出,再打印end456
t1=Thread(target=foo)
t2=Thread(target=bar)
t1.daemon=True # 只设置t1守护主线程
t1.start() # 启动t1
t2.start()
print("main-------") # 3 # 最后执行主线程 最后走主进程 主进程监测到子进程还没有结束,继续走,此时t1的守护时间已过,继续执行t1
# 输出
# 123
# 456
# main-------
# end123
# end456
# 守护子线程睡的久 其他非子线程和主线程都执行完了,守护子线程也结束,不再执行守护子线程的代码,end123不输出
from threading import Thread
import time
def foo():
print(123) # 1
time.sleep(3)
print("end123")
def bar():
print(456) # 2
time.sleep(1)
print("end456") # 4
t1=Thread(target=foo)
t2=Thread(target=bar)
t1.daemon=True
t1.start()
t2.start()
print("main-------") # 5
# 输出
# 123
# 456
# main-------
# end456
# 守护子线程和非子线程睡的时间一样,非子线程和主线程都结束了,守护线程也结束了,不再执行守护子线程的代码,end123不输出
from threading import Thread
import time
def foo():
print(123)
time.sleep(3)
print("end123")
def bar():
print(456)
time.sleep(1)
print("end456")
t1=Thread(target=foo)
t2=Thread(target=bar)
t1.daemon=True
t1.start()
t2.start()
print("main-------")
# 输出
# 123
# 456
# main-------
# end456
互斥锁
from threading import Thread
import time
import random
x = 100 # x被修改 x = 99
def task():# ①
global x # 再执行修改全局变量 x = 99
temp = x # ③ 先执行temp = 100,100个100
time.sleep(random.randint(1,3)) # 开始随机睡,有一个temp醒得快,开始往下走,其他的temp还在睡
# 其他的temp开始醒来,继续往下执行 都执行temp = 100-1 = 99(执行速度快会是99,慢的话,99~0都有可能)
temp = temp -1 # temp = 100-1 = 99
x = temp # x = 99
print(f'这些是子线程{x}')
# 先走函数def task ,函数里面的代码不执行
if __name__ == '__main__': # 走if开始执行接口
l1 = [] # 定义一个列表
for i in range(100): # ② 循环i 100次
t = Thread(target = task) # Thread(target = task)实例化一个子线程t,Thread是线程类 target = task 将task传入实例化对象中
l1.append(t) # 将实例化对象加入l1列表中,得到100个实例化对象
t.start() # start()调用函数,开始启动task里面的代码
print('开始启动子线程')
for i in l1: # ④ 循环100个实例化对象
i.join() # 每次都执行的子线程都会阻塞不执行主线程,使用for i in 其他的子线程是并发执行
print('阻塞子线程')
print(f'主线程{x}') # ⑤主线程99
from threading import Thread
import time
import random
x = 100
def task():
time.sleep(random.randint(1,2))
global x
temp = x
time.sleep(random.randint(1,3))
temp = temp -1
x = temp
if __name__ == '__main__':
l1 = []
for i in range(100):
t = Thread(target = task)
l1.append(t)
t.start()
for i in l1:
i.join()
print(f'主线程{x}') # 主线程98
from threading import Thread
import time
import random
x = 100
def task():
global x
temp = x
temp = temp -1
x = temp
if __name__ == '__main__':
l1 = []
for i in range(100):
t = Thread(target = task)
l1.append(t)
t.start()
for i in l1:
i.join()
print(f'主线程{x}') # 主线程0
# 多个任务共抢一个资源数据,保证数据的安全目的,要让其串行,串行可以用互斥锁
from threading import Thread
from threading import Lock
import time
import random
x = 100
def task(lock):
lock.acquire()
global x
temp = x
time.sleep(0.01)
temp = temp -1
x = temp
lock.release()
if __name__ == '__main__':
mutex = Lock()
l1 = []
for i in range(100):
t = Thread(target = task,args=(mutex,))
l1.append(t)
t.start()
time.sleep(3)
print(f'主线程{x}') #主线程0