锁丶threading.local丶线程池丶生产者消费者模型
一丶锁
线程安全:
线程安全能够保证多个线程同时执行时程序依旧运行正确, 而且要保证对于共享的数据,可以由多个线程存取,但是同一时刻只能有一个线程进行存取.
- import threading
- v = []
- def func(arg):
- v.append(arg) # 线程安全
- print(v)
- for i in range(10):
- t =threading.Thread(target=func,args=(i,))
- t.start()
线程安全
1.GIL锁
GIL锁中文名称为"全局解释器锁",主要体现在多线程中,每个线程在执行的过程中都需要先获取GIL,保证同一时刻只有一个线程可以执行代码.而Python语言和GIL没有半毛钱关系,仅仅是由于历史原因在Cpython虚拟机(解释器),难以移除GIL
补充:
(线程释放GIL锁的情况)在IO操作等可能会引起阻塞的system call之前,可以暂时释放GIL,但在执行完毕后,必须重新获取GIL. Python 3.x使用计时器(执行时间达到阈值后,当前线程释放GIL)或Python 2.x,tickets计数达到100,多线程爬取比单线程性能有所提升,因为遇到IO阻塞会自动释放GIL锁.
2.Lock锁(一次放一个)
- import threading
- import time
- v = []
- lock = threading.Lock()
- def func(arg):
- lock.acquire() #加锁
- # ++++++++++++++++++被锁的功能
- v.append(arg)
- time.sleep(0.01)
- m = v[-1]
- print(arg,m)
- #+++++++++++++++++++
- lock.release() #解锁
- for i in range(10):
- t =threading.Thread(target=func,args=(i,))
- t.start()
- # 不加锁: #加锁后
- # 2 9 0 0
- # 3 9 1 1
- # 0 9 2 2
- # 1 9 3 3
- # 7 9 4 4
- # 5 9 5 5
Lock
3.RLock锁(一次放一个)
- import threading
- import time
- v = []
- lock = threading.RLock()
- def func(arg):
- lock.acquire()
- lock.acquire()
- v.append(arg)
- time.sleep(0.01)
- m = v[-1]
- print(arg,m)
- lock.release()
- lock.release()
- for i in range(10):
- t =threading.Thread(target=func,args=(i,))
- t.start()
- # 结果:
- # 0 0
- # 1 1
- # 2 2
- # 3 3
- # 4 4
- # 5 5
RLock
Lock和RLock 的区别:
Lock:Lock(指令锁)是可用的最低级别的同步指令.Lock处于锁定状态时,不被特定的线程拥有.Lock包含两种状态--锁定和非锁定,以及两个基本方法.可以认为Lock有一个锁定值池,当线程请求锁定时,将线程至于池中,知道获得锁定后出池.池中的线程处于状态图中的同步阻塞状态.
RLock(可重入锁)是一个可以被同一个线程请求多次的同步指令.RLock使用了"拥有的线程"和"递归等级"的概念,处于锁定状态时,RLock被某个线程拥有.拥有RLock的线程可以再次调用acquire(),释放锁时需要调用release()相同次数.可以认为RLock包含一个锁定池和一个初始值为0的计数器,每次成功调用acquire()/release(),计数器将+1/-1,为0时锁处于未锁定状态
简言之: Lock属于全局,Rlock属于线程
4.BoundedSemaphore(一次放指定个数)
- import time
- import threading
- lock = threading.BoundedSemaphore(4) #每次允许通过的个数
- def func(arg):
- lock.acquire() #加锁
- print(arg)
- time.sleep(2)
- lock.release() #解锁
- for i in range(10):
- t =threading.Thread(target=func,args=(i,))
- t.start()
BoundedSemaphore
5.Condition(一次放多个)
- import time
- import threading
- lock = threading.Condition()
- # ############## 方式一:输入几个取出来几个 ##############
- def func(arg):
- print('线程进来了')
- lock.acquire()
- lock.wait() # 加锁
- print(arg)
- time.sleep(1)
- lock.release() #解锁
- for i in range(10):
- t =threading.Thread(target=func,args=(i,))
- t.start()
- while True:
- inp = int(input('>>>'))
- lock.acquire()
- lock.notify(inp)
- lock.release()
- #结果:
- # 线程进来了
- # ....
- # 线程进来了
- # >>>3
- # >>>0
- #
- #
- #
- # >>>3
- #
- #
- # >>>5
- #
- #
- #
- #
- # >>>9
- # ############## 方式二(输入一次放一个)##############
- #
- def xxxx():
- print('来执行函数了')
- input(">>>")
- # ct = threading.current_thread() # 获取当前线程
- # ct.getName()
- return True
- def func(arg):
- print('线程进来了')
- lock.wait_for(xxxx)
- print(arg)
- time.sleep(1)
- for i in range(10):
- t =threading.Thread(target=func,args=(i,))
- t.start()
- #结果
- # >> > 线程进来了
- # 来执行函数了
- # >> > 线程进来了
- # 来执行函数了
- # >> > 1
- #
- #
- #
- #
- #
- #
Condition
6.Event(一次放所有)
- import threading
- lock = threading.Event()
- def func(arg):
- print('线程来了')
- lock.wait() # 加锁:红灯
- print(arg)
- for i in range(10):
- t =threading.Thread(target=func,args=(i,))
- t.start()
- input(">>>>")
- lock.set() # 绿灯 获取
- lock.clear() # 再次变红灯
- for i in range(10):
- t =threading.Thread(target=func,args=(i,))
- t.start()
- input(">>>>")
- lock.set() #绿灯 获取
Event
二丶threading.local
作用:内部自动为每一个线程维护一个空间(字典),用于当前存取属于自己的值.保证线程之间的数据隔离
{
线程ID: {.....}
线程ID: {.....}
线程ID: {.....}
}
- import time
- import threading
- DATA_DICT = {}
- def func(arg):
- ident = threading.get_ident() #获取线程ID
- DATA_DICT[ident] = arg #{1756: 0, 2636: 1, 8892: 2, 8448: 3, 2344: 4, 7196: 5, 8572: 6, 2268: 7, 2480: 8, 7644: 9}
- time.sleep(1)
- print(DATA_DICT[ident],arg)
- for i in range(10):
- t =threading.Thread(target=func,args=(i,))
- t.start()
- import time
- import threading
- INFO = {}
- class Local(object):
- def __getattr__(self, item):
- ident = threading.get_ident()
- return INFO[ident][item]
- def __setattr__(self, key, value):
- ident = threading.get_ident()
- if ident in INFO:
- INFO[ident][key] = value
- else:
- INFO[ident] = {key:value}
- obj = Local()
- def func(arg):
- obj.phone = arg # 调用对象的 __setattr__方法(“phone”,1)
- time.sleep(2)
- print(obj.phone,arg)
- for i in range(10):
- t =threading.Thread(target=func,args=(i,))
- t.start()
- print(INFO)#{7688: {'phone': 0}, 8972: {'phone': 1}, 5280: {'phone': 2}, 4724: {'phone': 3},
- # 8384: {'phone': 4}, 8680: {'phone': 5}, 8220: {'phone': 6}, 9032: {'phone': 7}, 4660: {'phone': 8},
- # 528: {'phone': 9}}
三丶线程池 threadpool模块
可以模拟一个场景,假如我们要去领签名照,在工作室签名的明星只有两个在哪儿,而要领签名照的人很多很多,我们可以创建一个大纸箱子,把那些想要领签名照的人的信息记录下来,然后等明星按顺序来签名.这个大纸箱子就是我们所谓的线程池,存放一个个的需求等待CPU来调度
- from concurrent.futures import ThreadPoolExecutor
- import time
- def task(a1,a2):
- time.sleep(2)
- print(a1,a2)
- # 创建了一个线程池(最多5个线程)
- pool = ThreadPoolExecutor(5)
- for i in range(40):
- # 去线程池中申请一个线程,让线程执行task函数。
- pool.submit(task,i,8)
- import time
- import threading
- def task(arg):
- time.sleep(50)
- while True:
- num = input('>>>')
- t = threading.Thread(target=task,args=(num,))
- t.start()
线程
- import time
- from concurrent.futures import ThreadPoolExecutor
- def task(arg):
- time.sleep(10)
- print("========")
- pool = ThreadPoolExecutor(3)
- while True:
- num = input('>>>')
- pool.submit(task,num)
线程池
四丶生产者消费者模型
所谓生产者消费者模型就是生产者跟消费者的关系而已,就像厨师跟顾客一样,只有厨师做出来饭,顾客才能吃,如果厨师做不出来饭,顾客想吃也吃不到,只能排队等
- import time
- import queue
- import threading
- q = queue.Queue() # 线程安全
- def producer(id):
- """
- 生产者
- :return:
- """
- while True:
- time.sleep(2)
- q.put('包子')
- print('厨师%s 生产了一个包子' %id )
- for i in range(1,4):
- t = threading.Thread(target=producer,args=(i,))
- t.start()
- def consumer(id):
- """
- 消费者
- :return:
- """
- while True:
- time.sleep(1)
- v1 = q.get()
- print('顾客 %s 吃了一个包子' % id)
- for i in range(1,3):
- t = threading.Thread(target=consumer,args=(i,))
- t.start()
锁丶threading.local丶线程池丶生产者消费者模型的更多相关文章
- 线程锁、threading.local(flask源码中用的到)、线程池、生产者消费者模型
一.线程锁 线程安全,多线程操作时,内部会让所有线程排队处理.如:list/dict/Queue 线程不安全 + 人(锁) => 排队处理 1.RLock/Lock:一次放一个 a.创建10个线 ...
- 锁、threading.local、线程池
一.锁 Lock(1次放1个) 什么时候用到锁: 线程安全,多线程操作时,内部会让所有线程排队处理.如:list.dict.queue 线程不安全, import threading import t ...
- threading.local()方法;线程池
一,threading.local() import time import threading v = threading.local() def func(arg): # 内部会为当前线程创建一个 ...
- 进程同步控制(锁,信号量,事件), 进程通讯(队列和管道,生产者消费者模型) 数据共享(进程池和mutiprocess.Pool模块)
参考博客 https://www.cnblogs.com/xiao987334176/p/9025072.html#autoid-1-1-0 进程同步(multiprocess.Lock.Semaph ...
- 4、网络并发编程--僵尸进程、孤儿进程、守护进程、互斥锁、消息队列、IPC机制、生产者消费者模型、线程理论与实操
昨日内容回顾 操作系统发展史 1.穿孔卡片 CPU利用率极低 2.联机批处理系统 CPU效率有所提升 3.脱机批处理系统 CPU效率极大提升(现代计算机雏形) 多道技术(单核CPU) 串行:多个任务依 ...
- python并发编程之多进程(二):互斥锁(同步锁)&进程其他属性&进程间通信(queue)&生产者消费者模型
一,互斥锁,同步锁 进程之间数据不共享,但是共享同一套文件系统,所以访问同一个文件,或同一个打印终端,是没有问题的, 竞争带来的结果就是错乱,如何控制,就是加锁处理 part1:多个进程共享同一打印终 ...
- Python之路(第三十八篇) 并发编程:进程同步锁/互斥锁、信号量、事件、队列、生产者消费者模型
一.进程锁(同步锁/互斥锁) 进程之间数据不共享,但是共享同一套文件系统,所以访问同一个文件,或同一个打印终端,是没有问题的, 而共享带来的是竞争,竞争带来的结果就是错乱,如何控制,就是加锁处理. 例 ...
- python开发进程:互斥锁(同步锁)&进程其他属性&进程间通信(queue)&生产者消费者模型
一,互斥锁,同步锁 进程之间数据不共享,但是共享同一套文件系统,所以访问同一个文件,或同一个打印终端,是没有问题的, 竞争带来的结果就是错乱,如何控制,就是加锁处理 part1:多个进程共享同一打印终 ...
- java多线程:线程间通信——生产者消费者模型
一.背景 && 定义 多线程环境下,只要有并发问题,就要保证数据的安全性,一般指的是通过 synchronized 来进行同步. 另一个问题是,多个线程之间如何协作呢? 我们看一个仓库 ...
- 基于线程实现的生产者消费者模型(Object.wait(),Object.notify()方法)
需求背景 利用线程来模拟生产者和消费者模型 系统建模 这个系统涉及到三个角色,生产者,消费者,任务队列,三个角色之间的关系非常简单,生产者和消费者拥有一个任务队列的引用,生产者负责往队列中放置对象(i ...
随机推荐
- Ajax 执行流程 有用 一点
l 1.1使用JavaScript获得浏览器内置的AJAX引擎(XMLHttpRequest对象) l 1.2 通过AJAX引擎确定请求路径和请求参数 l 1.3 通知AJAX引擎发送请求 l AJA ...
- unreal3启动地图设置
在defaultengine.ini中[URL]节: Map=MOBATinyMap.udkLocalMap=MOBATinyMap.udk 这里有Map和LocalMap两个属性,让人有点混淆,只好 ...
- 8、SRR数据下载https://ftp-trace.ncbi.nlm.nih.gov/sra/sdk/2.8.2/
1.prefetch SRRxxxxxx -/ncbi/public/sra 2.fastq-dump --split-files xxxxxxsra 3.SRA.SAM以及Fastq ...
- ASE分析
1.Prepare necessary input files(可以参考上次的博客http://www.cnblogs.com/renping/p/7391028.html) 1)对fq1和fq2合并 ...
- java File基本操作,以及递归遍历文件夹
java 的文件操作,相对来说是比较重要的,无论是编写CS还是BS程序,都避免不了要与文件打交道,例如读写配置文件等.虽然现在很多框架都直接帮你做好了这一步! java.io.File 底层是调用与c ...
- 【linux-./configure 配置文件时出错问题】
环境是:centos 5.6 安装系统时,可能安装的是标准的精简版本,所以没有选择软件依赖包,很多软件都没有安装. 现在需要安装软件,安装软件时报错: make: *** 没有指明目标并且找不到 ma ...
- java基础之介绍
1.JAVA涉及在服务器领域上主要有 Linux.Unix.Windows等(其中Linux和Unix是大部分服务器用的主要的系统) 2.JAVA之所以发展的原因 1.java得到了很多的支持,拥有许 ...
- Idea设置签名
IntelliJ IDEA如何设置头注释,自定义author和date 下面这张图,保证你一看就会: 下面这个模板,你拿去改一改就行了. 1 /** 2 * @Author: Gosin 3 * ...
- CF987C Three displays 暴力
题意翻译 题目大意: nnn个位置,每个位置有两个属性s,cs,cs,c,要求选择3个位置i,j,ki,j,ki,j,k,使得si<sj<sks_i<s_j<s_ksi< ...
- luoguP4921 情侣?给我烧了!
luogu 考虑对于\(n\)对情侣,恰好\(k\)对是和谐的方案数是 \[ ans[n][k]=\binom{n}{k}A^k_n2^kg(n-k) \] \(g(n)\)为全部\(n\)对情侣不和 ...