python函数锁 python解锁

Python多线程总结在实际处理数据时python函数锁,因系统内存有限,我们不可能一次把所有数据都导出进行操作,所以需要批量导出依次操作 。为了加快运行,我们会采用多线程python函数锁的方法进行数据处理 , 以下为我总结python函数锁的多线程批量处理数据的模板:
主要分为三大部分:
共分4部分对多线程的内容进行总结 。
先为大家介绍线程的相关概念:
在飞车程序中,如果没有多线程,我们就不能一边听歌一边玩飞车,听歌与玩 游戏 不能并行;在使用多线程后,我们就可以在玩 游戏 的同时听背景音乐 。在这个例子中启动飞车程序就是一个进程,玩 游戏 和听音乐是两个线程 。
Python 提供了 threading 模块来实现多线程:
因为新建线程系统需要分配资源、终止线程系统需要回收资源,所以如果可以重用线程,则可以减去新建/终止的开销以提升性能 。同时,使用线程池的语法比自己新建线程执行线程更加简洁 。
Python 为我们提供了 ThreadPoolExecutor 来实现线程池,此线程池默认子线程守护 。它的适应场景为突发性大量请求或需要大量线程完成任务,但实际任务处理时间较短 。
其中max_workers 为线程池中的线程个数,常用的遍历方法有 map 和 submit as_completed。根据业务场景的不同,若我们需要输出结果按遍历顺序返回,我们就用 map 方法 , 若想谁先完成就返回谁,我们就用 submit as_complete 方法 。
我们把一个时间段内只允许一个线程使用的资源称为临界资源,对临界资源的访问 , 必须互斥的进行 。互斥,也称间接制约关系 。线程互斥指当一个线程访问某临界资源时,另一个想要访问该临界资源的线程必须等待 。当前访问临界资源的线程访问结束,释放该资源之后 , 另一个线程才能去访问临界资源 。锁的功能就是实现线程互斥 。
我把线程互斥比作厕所包间上大号的过程 , 因为包间里只有一个坑 , 所以只允许一个人进行大号 。当第一个人要上厕所时,会将门上上锁 , 这时如果第二个人也想大号,那就必须等第一个人上完,将锁解开后才能进行,在这期间第二个人就只能在门外等着 。这个过程与代码中使用锁的原理如出一辙 , 这里的坑就是临界资源 。Python 的 threading 模块引入了锁 。threading 模块提供了 Lock 类 , 它有如下方法加锁和释放锁:
我们会发现这个程序只会打印“第一道锁”,而且程序既没有终止,也没有继续运行 。这是因为Lock 锁在同一线程内第一次加锁之后还没有释放时 , 就进行了第二次 acquire 请求,导致无法执行 release , 所以锁永远无法释放,这就是死锁 。如果我们使用 RLock 就能正常运行,不会发生死锁的状态 。
在主线程中定义Lock 锁 , 然后上锁,再创建一个子 线程t 运行 main 函数释放锁,结果正常输出 , 说明主线程上的锁,可由子线程解锁 。
如果把上面的锁改为RLock 则报错 。在实际中设计程序时,我们会将每个功能分别封装成一个函数,每个函数中都可能会有临界区域,所以就需要用到 RLock。
一句话总结就是Lock 不能套娃 , RLock 可以套娃; Lock 可以由其他线程中的锁进行操作, RLock 只能由本线程进行操作 。
python log 文件锁判断是否有锁Python的文件锁目前使用的是fcntl这个库,它实际上为 Unix上的ioctl,flock和fcntl 函数提供了一个接口 。
1.fcntl库的简单使用
[python] view plain copy
import fcntl
import os, time
FILE = "counter.txt"
if not os.path.exists(FILE):
# create the counter file if it doesn't exist
file = open(FILE, "w")
file.write("0")
file.close()
for i in range(20):
file = open(FILE, "r ")#由于flock生成的是劝告锁,不能阻止进程对文件的操作,所以这里可以正常打开文件
fcntl.flock(file.fileno(), fcntl.LOCK_EX)#为了避免同时操作文件,需要程序自己来检查该文件是否已经被加锁 。这里如果检查到加锁了 , 进程会被阻塞
print 'acquire lock'
counter = int(file.readline())1
file.seek(0)
file.write(str(counter))
print os.getpid(), "=", counter
time.sleep(10)
file.close() # unlocks the file
print 'release lock'
time.sleep(3)
分别启动2个进程来同时运行这个脚本,我们可以很明显的看到2者互相之间交替阻塞 。同一时刻只有一个进程能够对counter.txt文件进行操作 。
2.对fcntl.flock()函数的说明:
linux的flock() 的函数原型如下所示:
int flock(int fd, int operation);
其中,参数 fd 表示文件描述符;参数 operation 指定要进行的锁操作,该参数的取值有如下几种:
LOCK_SH:表示要创建一个共享锁,在任意时间内 , 一个文件的共享锁可以被多个进程拥有;
LOCK_EX:表示创建一个排他锁,在任意时间内,一个文件的排他锁只能被一个进程拥有;
LOCK_UN:表示删除该进程创建的锁;
LOCK_MAND:它主要是用于共享模式强制锁,它可以与 LOCK_READ 或者 LOCK_WRITE联合起来使用,从而表示是否允许并发的读操作或者并发的写操作;
通常情况下,如果加锁请求不能被立即满足 , 那么系统调用 flock()会阻塞当前进程 。比如 , 进程想要请求一个排他锁,但此时,已经由其他进程获取了这个锁,那么该进程将会被阻塞 。如果想要在没有获得这个排他锁的情况下不阻塞该进程,可以将LOCK_NB 和 LOCK_SH 或者 LOCK_EX 联合使用,那么系统就不会阻塞该进程 。flock()所加的锁会对整个文件起作用 。
注意:
1. 对于文件的 close() 操作会使文件锁失效;
2. 同理 , 进程结束后文件锁失效;
3. flock() 的 LOCK_EX是“劝告锁” , 系统内核不会强制检查锁的状态 , 需要在代码中进行文件操作的地方显式检查才能生效 。
python多线程全局变量和锁1.python中数据类型python函数锁 , int,float,复数python函数锁 , 字符 , 元组 , 做全局变量时需要在函数里面用global申明变量 , 才能对变量进行操作 。
而 , 对象,列表,词典 , 不需要声明,直接就是全局的 。
2.线程锁mutex=threading.Lock()
创建后就是全局的 。线程调用函数可以直接在函数中使用 。
mutex.acquire()开启锁
mutex=release()关闭锁
要注意,死锁的情况发生 。
注意运行效率的变化:
正常1秒,完成56997921
加锁之后,1秒只运行python函数锁了531187,相差10倍多 。
3.继承.threading.Thread的类,无法调用__init__函数 , 无法在创建对象时初始化新建的属性 。
4.线程在cpu的执行 , 有随机性
5. 新建线程时 , 需要传参数时,args是一个元组,如果只有一个参数,一定后面要加一个,符号 。不能只有一个参数否则线程会报创建参数错误 。threading.Thread(target=fuc,args=(arg,))
Python中的各种锁?大致罗列一下:
一、全局解释器锁(GIL)
1、什么是全局解释器锁
每个CPU在同一时间只能执行一个线程,那么其他的线程就必须等待该线程的全局解释器,使用权消失后才能使用全局解释器,即使多个线程直接不会相互影响在同一个进程下也只有一个线程使用cpu,这样的机制称为全局解释器锁(GIL) 。GIL的设计简化了CPython的实现,使的对象模型包括关键的内建类型,如:字典等,都是隐含的,可以并发访问的,锁住全局解释器使得比较容易的实现对多线程的支持,但也损失了多处理器主机的并行计算能力 。
2、全局解释器锁的好处
1)、避免了大量的加锁解锁的好处
2)、使数据更加安全,解决多线程间的数据完整性和状态同步
3、全局解释器的缺点
多核处理器退化成单核处理器,只能并发不能并行 。
4、GIL的作用:
多线程情况下必须存在资源的竞争,GIL是为了保证在解释器级别的线程唯一使用共享资源(cpu) 。
二、同步锁
1、什么是同步锁?
同一时刻的一个进程下的一个线程只能使用一个cpu,要确保这个线程下的程序在一段时间内被cpu执,那么就要用到同步锁 。
2、为什么用同步锁?
因为有可能当一个线程在使用cpu时,该线程下的程序可能会遇到io操作,那么cpu就会切到别的线程上去,这样就有可能会影响到该程序结果的完整性 。
3、怎么使用同步锁?
只需要在对公共数据的操作前后加上上锁和释放锁的操作即可 。
4、同步锁的所用:
为了保证解释器级别下的自己编写的程序唯一使用共享资源产生了同步锁 。
三、死锁
1、什么是死锁?
指两个或两个以上的线程或进程在执行程序的过程中,因争夺资源或者程序推进顺序不当而相互等待的一个现象 。
2、死锁产生的必要条件?
互斥条件、请求和保持条件、不剥夺条件、环路等待条件
3、处理死锁的基本方法?
预防死锁、避免死锁(银行家算法)、检测死锁(资源分配)、解除死锁:剥夺资源、撤销进程
四、递归锁
【python函数锁 python解锁】在Python中为了支持同一个线程中多次请求同一资源,Python提供了可重入锁 。这个RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数 , 从而使得资源可以被多次require 。直到一个线程所有的acquire都被release , 其他的线程才能获得资源 。递归锁分为可递归锁与非递归锁 。
五、乐观锁
假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性 。
六、悲观锁
假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作 。
python常用的加锁方式:互斥锁、可重入锁、迭代死锁、互相调用死锁、自旋锁大致罗列一下:
一、全局解释器锁(GIL)
1、什么是全局解释器锁
每个CPU在同一时间只能执行一个线程,那么其他的线程就必须等待该线程的全局解释器 , 使用权消失后才能使用全局解释器,即使多个线程直接不会相互影响在同一个进程下也只有一个线程使用cpu,这样的机制称为全局解释器锁(GIL) 。GIL的设计简化了CPython的实现,使的对象模型包括关键的内建类型,如:字典等 , 都是隐含的,可以并发访问的,锁住全局解释器使得比较容易的实现对多线程的支持,但也损失了多处理器主机的并行计算能力 。
2、全局解释器锁的好处
1)、避免了大量的加锁解锁的好处
2)、使数据更加安全,解决多线程间的数据完整性和状态同步
3、全局解释器的缺点
多核处理器退化成单核处理器,只能并发不能并行 。
4、GIL的作用:
多线程情况下必须存在资源的竞争,GIL是为了保证在解释器级别的线程唯一使用共享资源(cpu) 。
二、同步锁
1、什么是同步锁?
同一时刻的一个进程下的一个线程只能使用一个cpu,要确保这个线程下的程序在一段时间内被cpu执,那么就要用到同步锁 。
2、为什么用同步锁?
因为有可能当一个线程在使用cpu时 , 该线程下的程序可能会遇到io操作,那么cpu就会切到别的线程上去,这样就有可能会影响到该程序结果的完整性 。
3、怎么使用同步锁?
只需要在对公共数据的操作前后加上上锁和释放锁的操作即可 。
4、同步锁的所用:
为了保证解释器级别下的自己编写的程序唯一使用共享资源产生了同步锁 。
三、死锁
1、什么是死锁?
指两个或两个以上的线程或进程在执行程序的过程中,因争夺资源或者程序推进顺序不当而相互等待的一个现象 。
2、死锁产生的必要条件?
互斥条件、请求和保持条件、不剥夺条件、环路等待条件
3、处理死锁的基本方法?
预防死锁、避免死锁(银行家算法)、检测死锁(资源分配)、解除死锁:剥夺资源、撤销进程
四、递归锁
在Python中为了支持同一个线程中多次请求同一资源,Python提供了可重入锁 。这个RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require 。直到一个线程所有的acquire都被release,其他的线程才能获得资源 。递归锁分为可递归锁与非递归锁 。
五、乐观锁
假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性 。
六、悲观锁
假定会发生并发冲突 , 屏蔽一切可能违反数据完整性的操作 。
python常用的加锁方式:互斥锁、可重入锁、迭代死锁、互相调用死锁、自旋锁
Python中级精华-临界区加锁概念梳理:
临界区:
临界区指的是一个访问共用资源(例如:共用设备或是共用存储器)的程序片段
,而这些共用资源又无法同时被多个线程访问的特性 。当有线程进入临界区段时,其他线程或是进程必须等待,有一些同步的机制必须在临界区段的进入点与离开点实现,以确保这些共用资源是被互斥获得使用 。
目的:
我们在多线程
处理是,经常会涉及到对于一块共享资源的访问,这里就需要线程可以互斥去避免出现竞态条件(race condition).
方法:
要想让可变对象安全地在多线程环境中进行访问,就要使用锁变量(threading中的LockRLock) , 锁变量也是同步原语
中的最常见一种之一 。
示例:
线程的调度从本质上来说是非确定性的(只能保证独一访问 , 但保证不了谁先谁后) 。只要共享的可变状态需要被多个线程访问,就要使用锁机制,保证数据的安全 。
在threading库中我们也发现了其他的同步原语例如:RLock(可重入锁)、Semaphore对象(信号量) 。
RLock:可以被同一个线程多次获取 , 主要用来编写基于锁的代码,或者基于‘监听器’的同步处理 。
当某个类持有这种类型锁时,只有一个线程可以使用类中全部函数或者方法,例如:
这份代码中只有一个作用于整个类的锁,它被所有的类实例所共享,不再将所绑定在某个实例的可变状态上,现在这个锁是用来同步类中的方法的 。对于其他标准锁不同的是 , 对于已经持有了该锁的方法可以调用同样使用了这个锁的其他方法(参考sub_one()) 。
这个实现的特点是,无论创建了多少counter实例,这些实例共有同一把锁 。因此 , 当有大量counter出现时,这种方法堆内存的使用效率要高很多 。但是可能存在的缺点是在使用了大量线程且需要频繁更新counter中的数据时 , 这么做会出现锁争用的情况 。
另外一种同步原语semaphore,是一种基于共享计数器的同步原语 。如果计数器非0,那么with语句会递减计数器并且允许线程继续执行 。当with语句块结束后,会将计数器递增 。如果计数器为0,那么执行过程会被阻塞,直到由另外一个线程来递增计数器为止 。由于信号量
的实现更为复杂,这会对程序带来一定的负面影响 。除了简单地加锁功能外,信号量对象对于那些设计在线程间发送信号或者需要实现节流处理的应用中更加有用,例如限制并发总数:
浅谈Python中的线程锁竞争条件 是并发编程中的一个重要问题 。当一个线程试图修改共享资源 的同时,另一个线程正在修改该资源时,就会出现这种情况——这会导致输出乱码 , 这就是线程需要同步的原因 。
Python的threading模块包括 Lock 作为同步工具 。锁有两种状态:
可以使用该acquire()方法锁定锁 。一旦一个线程获得了锁,所有后续的获取锁的尝试都会被阻塞,直到它被释放 。可以使用该release()方法释放锁 。
以下代码通过一个简单的示例展示了如何在 Python 中使用锁:
假设银行账户中有 100 美元 。每个月存入 10 美元作为利润,扣除 10 美元支付账单 。thread1用于存入利润,而thread2用于支付账单 。在某些月份,利润会在账单支付后存入 。但是,这不应影响帐户中的最终金额 。
由于 竞争条件下 , 以下代码得到的结果可能不正确 。可能会出现一个线程在上下文切换前无法将更新后的值写入共享变量deposit,而另一个线程读取到未更新的值的情况;因此,导致不可预测的结果 。
运行以上代码,将输出
acquire()和release()方法之间的代码是 原子 执行的,因此在另一个线程已经进行更改之后,一个线程不可能读取未更新的版本 。
运行以上程序,将输出:
关于python函数锁和python解锁的介绍到此就结束了 , 不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站 。

    推荐阅读