Python高级学习第三课(寒假)2022-1-7

本文详细介绍了Python中的多线程创建方法,包括函数方式和类方式,并通过示例展示了线程同步机制——线程锁的使用,防止多个线程对共享资源的并发修改导致的问题。同时,还探讨了递归锁(RLock)在解决死锁问题中的应用。
摘要由CSDN通过智能技术生成

多线程

注: 本文章仅为学习笔记
完整视频讲解

  1. 线程是程序执行的最小单位,而进程是操作系统分配资源的最小单位;
  2. 一个进程由一个或多个线程组成,线程是一个进程中代码的不同执行路线;
  3. 进程之间相互独立,但同一进程下的各个线程之间共享程序的内存空间(包括代码段,数据集,堆等)及一些进程级的资源(如打开文件和信号等),某进程内的线程再其他进程不可见;
  4. 调度和切换:线程上下文切换比进程上下文切换要快得多

创建多线程

不使用多线程的时候,此处代码运行,需要6秒程序才能结束

def test(x):
    print(x)
    time.sleep(3) #设置隔两秒打印一个x


start_time = time.time()
test(1)
test(2)
print(f"共运行了{time.time()-start_time}秒")

运行结果:

1
2
共运行了6.002071380615234

创建多线程方法一:用函数创建线程

调用threading库的Thread类

python3中,提供了一个内置模块threading.Thread,可以很方便的创建多线程,threading.Thread()一般接收2个参数:
线程函数名:要放置线程让其后台执行的函数,由用户自己定义,如:target=test 注意不要加()
线程函数的参数: 线程函数名所需的参数,以tuple形式传入,如果不需要参数,可以不指定。

#自定义线程函数
def test(x):
    print(x)
    time.sleep(3) #设置隔两秒打印一个x
    
#创建线程t1,指定参数为1
t1 = threading.Thread(target=test,args=(1,))  #target设置执行目标 *args元组,**kwargs字典
#创建线程t2,指定参数为2
t2 = threading.Thread(target=test,args=(2,))
start_time = time.time()
#启动线程t1
t1.start()
#启动线程t2
t2.start()    
print(f"共运行了{time.time()-start_time}秒")

运行结果:

1
2
共运行了0.0009975433349609375

创建多线程方法二:用类创建线程
自定义一个类,该类必须继承threading.Thread这个父类,必须重写run()这个方法。

这个run()方法相当于第一种方法中的线程函数,可以写自己需要的业务逻辑代码,在start()后将会调用。

def test(x):
    print(x)
    time.sleep(3) #设置隔两秒打印一个x
#用类创建线程,继承threading.Thread
class MyThread(threading.Thread):
    def __init__(self,n):
        super(MyThread,self).__init__()
        self.n = n
    #重写run方法
    def run(self):
        print("以类的方式创建多线程",self.n)
        
r1 = MyThread(11)
r2 = MyThread(22)
start_time = time.time()
r1.start()
r2.start()
print(f"共运行了{time.time()-start_time}秒")

运行结果:

以类的方式创建多线程 11
以类的方式创建多线程 22
共运行了0.0012888908386230469

线程锁

为什么需要线程锁?
多个线程对同一个数据进行修改时, 可能会出现不可预料的情况.

如何实现线程锁?

  1. 实例化一个锁对象;
    lock = threading.Lock()
  2. 操作变量之前进行加锁
    lock.acquire()
  3. 操作变量之后进行解锁
    lock.release()
def run():
    global x #设置全体变量
    lock.acquire() #操作变量之前进行加锁
    x += 1
    lock.release()  #操作变量之后进行解锁

if __name__ == '__main__':
    x = 0 #定义变量x
    res = [] #定义列表
    lock = threading.Lock() #实例化一个锁对象
    #创建多线程
    for i in range(100):
        t = threading.Thread(target=run)
        t.start()
        res.append(t) #写入列表
    for t in res:
        t.join()
    print(x)

递归锁

假设创建一把锁,线程会卡死,为死锁

"""递归锁"""
import threading


def run1():
    global x
    lock.acquire()  # 操作变量之前进行加锁
    x += 1
    lock.release()  # 操作变量之后进行解锁
    return x

def run2():
    global y
    lock.acquire()  # 操作变量之前进行加锁
    y += 1

    lock.release()  # 操作变量之后进行解锁
    return y

def run3():
    lock.acquire()  # 操作变量之前进行加锁
    res1 = run1()
    res2 = run2()
    lock.release()  # 操作变量之后进行解锁
    print(res1,res2)

if __name__ == '__main__':
    x = 0
    y = 0
    lock = threading.RLock() #实例化一个锁对象
    for i in range(50):
        t = threading.Thread(target=run3)
        t.start()

    while threading.active_count() != 1:
        print(f'正在运行{threading.active_count()}个线程')
    print('线程运行结束!')

运行结果:
此时线程会卡死,为死锁
在这里插入图片描述
解决方法:
使用递归锁threading.RLock()

递归锁:RLcok类的用法和Lock类一样,支持嵌套,在多个锁没有释放的时候一般会使用RLock类

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值