首页 > 其他分享 >threading 模块的类 Lock 的基本使用

threading 模块的类 Lock 的基本使用

时间:2023-01-25 19:23:19浏览次数:44  
标签:Lock sum t1 threading 线程 模块 lock 1000

1. 简介
在多线程应用中,某个资源被多个线程共享访问,线程通过使用锁独占该资源。需要独占访问的资源可能是:

打印机,线程在使用打印机时,不允许其它线程向打印机输出
共享变量,线程对这个变量进行读取访问时,不允许其它线程同时对这个变量进行读取访问
python 的 threading 模块提供了类 Lock 用于独占访问某个共享资源,类 Lock 提供了如下方法:

方法 功能
acquire() 获得锁,如果锁是空闲的,则立即返回;如果锁已经被其它线程占用了,则阻塞等待。
release() 释放锁,唤醒等待该锁的线程。
线程在独占使用某个资源前,需要调用 lock.acquire() 方法,使用完毕后,需要调用 lock.release() 方法,如下所示:

lock = threading.Lock()

lock.acquire()
独占访问某个资源
lock.release()
2. 数据竞争
当多个线程在读写某个共享变量时,其最终的结果依赖于线程的执行顺序,这种现象被称为数据竞争,示例如下:

import threading

sum = 0
tmp = 0
引入模块 threading
设定全局变量 sum 和 tmp 的初值为 0,它们被线程共享访问
def thread_entry():
global sum, tmp

for i in range(1000 * 1000):
tmp = sum + 1
sum = tmp
在第 1 行,定义线程入口 thread_entry
在第 2 行,声明共享变量 sum 和 tmp
在第 4 行,for 循环 1000* 1000 次,递增变量 sum
t0 = threading.Thread(target = thread_entry, args = ())
t1 = threading.Thread(target = thread_entry, args = ())
t0.start()
t1.start()
t0.join()
t1.join()
print('sum =', sum)
创建线程 t0,线程入口为 thread_entry
线程 t0 对变量 sum 递增 1000 * 1000 次
创建线程 t1,线程入口为 thread_entry
线程 t1 对变量 sum 递增 1000 * 1000 次
等待两个线程结束后,打印 sum 的值
线程 t0 对变量 sum 递增 1000 * 1000 次
线程 t1 对变量 sum 递增 1000 * 1000 次
第一次运行程序,输出结果如下:

sum = 1464661
再次运行程序,输出结果如下:

sum = 1415592
线程 t0 和 t1 对 sum 各自递增 1000 * 1000 次,期望最终的 sum 为 2 * 1000 * 1000。然而,线程 t0 和 线程 t1 共享访问变量 sum 和 tmp,存在数据竞争,导致:

实际结果依赖于线程的执行顺序,每次执行程序的输出结果都不一样
实际结果和预期不一致
3. 使用 lock 防止数据竞争
可以使用 threading 模块的类 Lock 防止数据竞争,示例如下:

import threading

sum = 0
tmp = 0

def thread_entry():
global sum, tmp

for i in range(1000 * 1000):
lock.acquire() # 获取锁
tmp = sum + 1
sum = tmp
lock.release() # 释放锁

lock = threading.Lock() # 初始化锁
t0 = threading.Thread(target = thread_entry, args = ())
t1 = threading.Thread(target = thread_entry, args = ())
t0.start()
t1.start()
t0.join()
t1.join()
print('sum =', sum)

和上个小节的例子相比,增加了 3 行代码 (使用注释标记):

lock.acquire(),访问共享变量 sum 和 tmp 前,需要获取锁
lock.release(),访问共享变量 sum 和 tmp 后,需要释放锁
lock = thread.Lock(),初始化锁
第一次运行程序,输出结果如下:

sum = 200000
再次运行程序,输出结果如下:

sum = 200000
线程 t0 和 t1 对 sum 各自递增 1000 * 1000 次,期望最终的 sum 为 2 * 1000 * 1000。使用了 lock 防止了数据竞争:

每次执行程序的输出结果都是相同的
实际结果和期望结果相符合

标签:Lock,sum,t1,threading,线程,模块,lock,1000
From: https://www.cnblogs.com/10zhan/p/17067154.html

相关文章

  • 学习方法:模块学习法
    学习方法:模块学习法    学习分为两部分,模块学习和模块组合。  模块。任何一个学科,有很多独立的模块组成。模块,是组成一个学科的单位。模块,是一个学......
  • 静态Web服务器-多任务版Python解释器详解实现代理池的API模块
    学习目标能够写出多线程版的多任务web服务器程序1.静态Web服务器的问题目前的Web服务器,不能支持多用户同时访问,只能一个一个的处理客户端的请求,那么如何开发多任务版的web......
  • Mysql之分组查询Python解释器详解实现代理池的API模块
    学习目标能够写出分组查询的SQL语句1.分组查询介绍分组查询就是将查询结果按照指定字段进行分组,字段中数据相等的分为一组。分组查询基本的语法格式如下:GROUPBY列名[HAV......
  • block
    block可以将多个task任务组合在一起执行,支持when判断,支持类似python中的try语句。python语法举例:try:print(1/0)except:print(2)finally:print(3)......
  • 命令行客户端MySQL的使用Python解释器详解实现代理池的API模块
    学习目标能够知道使用命令行连接数据库命令能够写出增、删、改、查的SQL语句一、登录和登出数据库登录数据库:输入下面命令:mysql-uroot-p说明:-u后面是登录的用户名-p......
  • MySQL之排序查询与分页查询Python解释器详解实现代理池的API模块
    一、排序查询语法排序查询语法:select*from表名orderby列1asc|desc[,列2asc|desc,...]语法说明:先按照列1进行排序,如果列1的值相同时,则按照列2排序,以此类推asc......
  • mysql中常见的聚合函数Python解释器详解实现代理池的API模块
    1.聚合函数的介绍聚合函数又叫组函数,通常是对表中的数据进行统计和计算,一般结合分组(groupby)来使用,用于统计和计算分组数据。常用的聚合函数:count(col):表示求指定列的......
  • block
    block可以将多个task任务组合在一起执行,支持when判断,支持类似python中的try语句。python语法举例:try:print(1/0)except:print(2)finally:print(3)......
  • 黑马程序员前端-CSS综合案例:学成在线模块添加
     前端学习笔记教程不定期更新中,传送门:​​前端HTML第一天:什么是网页?什么是HTML?网页怎么形成?​​​​黑马程序员前端-CSS入门总结​​​​黑马程序员前端-CSS之emmet语法​......
  • Idea项目--多模块项目(淘淘商城)
    Idea项目--多模块项目(淘淘商城)https://blog.csdn.net/feiying0canglang/article/details/104225755 只要是父模块,maven项目类型就必须是pom类型。 idea搭建淘淘商城......