分配资源的基本单位,一旦创建一个进程就会分配一定的资源。
线程是cpu调度的基本单位,每个进程,每个进程至少都有一个线程,而这个线程就是我们通常说的主线程
线程之间数据可以共享,进程之间数据相互隔离(注:这里的线程应该是一个进程内的线程之间)
import threading
import time
def music(name,num):
for i in range(1,num):
time.sleep(0.1)#模拟耗时操作
print(f'{name}听第{i}遍音乐中!')
def coding(name,num):
for i in range(1,num):
time.sleep(0.1)
print(f'{name}编写第{i}遍代码中...')
if __name__ == '__main__':
t1=threading.Thread(target=music,args=('kkk',11))
t2=threading.Thread(target=coding,kwargs={'name':'sss','num':11})
for i range(5):#t1,t2未启动不会争抢
print("main启动")
t1.start()
t2.start()线程的注意点
1,线程之间执行是无序的(原因:下面的CPU调度资源策略)
2,主线程会等待所有的子线程执行结束再结束
和守护进程类似,thread(target=show, daemon=True)或者t1.setDaemon(True)
3,线程之间会共享全局变量
4,多线程之间共享全局变量数据会出现错误问题,可以用互斥锁解决
出错原因:当线程1在使用全局变量时,线程2也在使用,当一返回值时,二也返回,但这样就造成了返回了两次但只造成一次数值变换
解决:线程同步,保证同一时刻只有一个线程去操作全局变量
同步:就是协同步调,按预定的先后次序进行运行
import threading
import time
global_num=0
def sum_func1():
global global_num
for i in range(1000000):
global_num+=1
print(f"sum_func1的执行结果为{global_num}")
def sum_func2():
global global_num
for i in range(1000000):
global_num+=1
print(f"sum_func2的执行结果为{global_num}")
if __name__ == '__main__':
t1=threading.Thread(target=sum_func1)
t2=threading.Thread(target=sum_func2)
t1.start()
t2.start()sum_func1的执行结果为1314943
sum_func2的执行结果为2000000CPU调度资源的策略:
1,均分时间片(可能会导致资源闲置,即可能不需要资源的线程也分到一部分资源)
2,抢占式调度(谁要谁就去抢资源)
互斥锁:共享数据进行锁定
死锁:一直等待对方释放锁的情景
产生原因:未在合适地方释放锁
结果:程序无法执行下去
import threading
mutex=threading.Lock()
global_num=0
def sum_func1():
mutex.acquire()
global global_num
for i in range(1000000):
global_num+=1
print(f"sum_func1的执行结果为{global_num}")
mutex.release()
def sum_func2():
mutex.acquire()
global global_num
for i in range(1000000):
global_num+=1
print(f"sum_func2的执行结果为{global_num}")
mutex.release()
if __name__ == '__main__':
t1=threading.Thread(target=sum_func1)
t2=threading.Thread(target=sum_func2)
t1.start()
t2.start()创建,上锁,释放锁
threading.Lock();mutex.acquire();mutex.release()
使用互斥锁时可能会导致死锁或者锁不住
线程进程对比
线程依赖进程,进程时CPU分配资源的基本单位,线程是CPU调度资源的基本单位
进程更消耗资源,不能共享全局变量,相对更稳定
线程更轻量级,可以共享全局变量,相对更灵活