线程锁、threading.local(flask源码中用的到)、线程池、生产者消费者模型
一、线程锁
线程安全,多线程操作时,内部会让所有线程排队处理。如:list/dict/Queue
线程不安全 + 人(锁) => 排队处理
1、RLock/Lock:一次放一个
a、创建10个线程,在列表中追加自己,如下代码:
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()
b、创建10个线程,把自己添加到列表中,再读取列表的最后一个,如下代码:
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()
注意:RLock和Lock用法一样,只是Lock只能锁一次解一次,RLock支持锁多次解多次,以后用RLock。
2、BoundedSemaphore(n) ,信号量, 一次放n个,如下代码:
import threading
import time lock = threading.BoundedSemaphore(3) def func(arg):
lock.acquire() # 加锁
time.sleep(1)
print(arg)
lock.release() # 释放锁 for i in range(10):
t = threading.Thread(target=func, args=(i,))
t.start()
3、condition(),一次放x个,x可由用户动态输入,代码如下:
1)方式一:
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()
2)方式二:
import time
import threading lock = threading.Condition()
def f1():
print('来执行函数了')
input(">>>")
return True def func(arg):
print('线程进来了')
lock.wait_for(f1) # 等函数f1执行完毕后继续往下走
print(arg)
time.sleep(1) for i in range(10):
t =threading.Thread(target=func,args=(i,))
t.start()
4、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()
总结:
线程安全,列表和字典线程安全;
为什么要加锁? 非线程安全,控制一段代码;
二、threading.local()
作用:内部自动为每个线程维护一个空间(本质是字典),用于当前线程存取属于自己的值,保证线程之间的数据隔离。
{
线程ID : { . . . },
线程ID : { . . . },
线程ID : { . . . },
线程ID : { . . . },
}
"""
以后:Flask框架内部看到源码 上下文管理 """
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()
threading.local()的原理:
import threading
import time v = threading.local() def func(arg):
v.phone = arg # 内部会为当前线程创建一个空间用于存储:phone = 自己的值
time.sleep(2)
print(v.phone,arg) # 去当前线程自己空间取值 for i in range(10):
t = threading.Thread(target=func, args=(i,))
t.start()
threading.local()的使用:
三、线程池
以后写代码不要一个一个创建线程,而是创建一个线程池,再去线程池申请线程去执行任务,如下示例:
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)
四、生产者消费者模型
三部分:生产者,消费者,队列
队列:先进先出
栈:后进先出
问题1:生产者消费者模型解决了什么问题?不用一直等待的问题。如下示例:
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)
v = q.get()
print('顾客 %s 吃了一个%s' % (id,v)) for i in range(1,3):
t = threading.Thread(target=consumer,args=(i,))
t.start()
五、面向对象补充(了解,以后不会写,flask源码中会遇到)
class Foo(object):
def __init__(self):
self.name = 'alex'
def __setattr__(self, key, value):
print(key,value)
obj = Foo() # 结果为:name alex (说明执行了Foo的__setattr__方法)
# 分析:因为obj.x自动执行__setattr__
print(obj.name) # 报错
# 分析:__setattr__方法中没有设置的操作,只有打印
示例一:
class Foo(object):
def __init__(self):
object.__setattr__(self, 'info', {}) # 在对象中设置值的本质
def __setattr__(self, key, value):
self.info[key] = value
def __getattr__(self, item):
return self.info[item]
obj = Foo()
obj.name = 'alex'
print(obj.name)
示例二:
线程锁、threading.local(flask源码中用的到)、线程池、生产者消费者模型的更多相关文章
- 线程锁,threadinglocal,线程池,生产者消费者模型
1.线程锁 1.锁Lock(只能锁一次) import threading import time v = [] lock = threading.Lock() def func(arg): lock ...
- 4、网络并发编程--僵尸进程、孤儿进程、守护进程、互斥锁、消息队列、IPC机制、生产者消费者模型、线程理论与实操
昨日内容回顾 操作系统发展史 1.穿孔卡片 CPU利用率极低 2.联机批处理系统 CPU效率有所提升 3.脱机批处理系统 CPU效率极大提升(现代计算机雏形) 多道技术(单核CPU) 串行:多个任务依 ...
- 第23章 java线程通信——生产者/消费者模型案例
第23章 java线程通信--生产者/消费者模型案例 1.案例: package com.rocco; /** * 生产者消费者问题,涉及到几个类 * 第一,这个问题本身就是一个类,即主类 * 第二, ...
- flask 源码专题(十一):LocalStack和Local对象实现栈的管理
目录 04 LocalStack和Local对象实现栈的管理 1.源码入口 1. flask源码关于local的实现 2. flask源码关于localstack的实现 3. 总结 04 LocalS ...
- 04 flask源码剖析之LocalStack和Local对象实现栈的管理
04 LocalStack和Local对象实现栈的管理 目录 04 LocalStack和Local对象实现栈的管理 1.源码入口 1. flask源码关于local的实现 2. flask源码关于l ...
- Flask源码关于local的实现
flask源码关于local的实现 try: # 协程 from greenlet import getcurrent as get_ident except ImportError: try: fr ...
- 锁丶threading.local丶线程池丶生产者消费者模型
一丶锁 线程安全: 线程安全能够保证多个线程同时执行时程序依旧运行正确, 而且要保证对于共享的数据,可以由多个线程存取,但是同一时刻只能有一个线程进行存取. import threading v = ...
- 用尽洪荒之力学习Flask源码
WSGIapp.run()werkzeug@app.route('/')ContextLocalLocalStackLocalProxyContext CreateStack pushStack po ...
- Flask 源码流程,上下文管理
源码流程 创建对象 from flask import Flask """ 1 实例化对象 app """ app = Flask(__na ...
随机推荐
- gitlab 6 安装备忘录
gitlab 6.2-stable;Ubuntu 13.10;ruby 2.0.0 推荐使用PostgreSQL,MySQL不同版本可能碰到兼容性问题(www.oschina.net/question ...
- Atitit. 真正的全中国文字attilax易语言的特点以及范例
Atitit. 真正的全中国文字attilax易语言的特点以及范例 1. 前言 attilax易语言是什么??1 2. attilax易语言的特点2 2.1. 支持多语言文字,不只汉字,还有藏文,维文 ...
- MapReduce-MulitipleOutputs实现自己定义输出到多个文件夹
输入源数据例子: Source1-0001 Source2-0002 Source1-0003 Source2-0004 Source1-0005 Source2-0006 Source3-0007 ...
- NPOI读取操作excel
.读取using (FileStream stream = new FileStream(@"c:\客户资料.xls", FileMode.Open, FileAccess.Rea ...
- 学习抓包之如何用Charles实现“刷楼”
为了获取一些网络中的数据,我们需要掌握抓包技术. Charles是一个 HTTP 代理服务器, HTTP 监视器,反转代理服务器.它允许一个开发者查看所有连接互联网的 HTTP 通信.这些包括Requ ...
- 设置一个label显示多种颜色,多种字体大小
UILabel* label = [[UILabel alloc] init]; label.frame = CGRectMake(0, 100, 200, 100); label.textColor ...
- Extjs中获取getEl获取undefined的问题
一定注意: getEl()方法只有在panel.show()之后才会有值.在hide()的时候没有该对象. 也就是说如果要操作Ext.dom.Element对象必须让对象先显示出来.
- 如何解决局域网中Windows防火墙不能访问Oracle问题!
在防火墙例外中,添加端口1521端口就样局域网内的其他机器就可以访问你的ORACLE了. 在防火墙的入站规则中,新建端口规则.过程如下例图片所示:
- Java并发编程(七)线程封闭
当访问共享的可变数据时,通常需要使用同步.一种避免使用同步的方式就是不共享数据. 如果仅在单线程内访问数据,就不需要同步.这种技术被称为线程封闭(Thread Confinement),它是实现线程安 ...
- Swoole系列(一):简介
前言: 实际上作为一名PHP程序员,我很清楚PHP的确有很多局限性,比如Unix系统编程.网络通信编程.异步io,大部分PHPer不懂.PHP界也确实没有这样的东西.Swoole开源项目就是为了弥补P ...