一、线程锁

  线程安全,多线程操作时,内部会让所有线程排队处理。如: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源码中用的到)、线程池、生产者消费者模型的更多相关文章

  1. 线程锁,threadinglocal,线程池,生产者消费者模型

    1.线程锁 1.锁Lock(只能锁一次) import threading import time v = [] lock = threading.Lock() def func(arg): lock ...

  2. 4、网络并发编程--僵尸进程、孤儿进程、守护进程、互斥锁、消息队列、IPC机制、生产者消费者模型、线程理论与实操

    昨日内容回顾 操作系统发展史 1.穿孔卡片 CPU利用率极低 2.联机批处理系统 CPU效率有所提升 3.脱机批处理系统 CPU效率极大提升(现代计算机雏形) 多道技术(单核CPU) 串行:多个任务依 ...

  3. 第23章 java线程通信——生产者/消费者模型案例

    第23章 java线程通信--生产者/消费者模型案例 1.案例: package com.rocco; /** * 生产者消费者问题,涉及到几个类 * 第一,这个问题本身就是一个类,即主类 * 第二, ...

  4. flask 源码专题(十一):LocalStack和Local对象实现栈的管理

    目录 04 LocalStack和Local对象实现栈的管理 1.源码入口 1. flask源码关于local的实现 2. flask源码关于localstack的实现 3. 总结 04 LocalS ...

  5. 04 flask源码剖析之LocalStack和Local对象实现栈的管理

    04 LocalStack和Local对象实现栈的管理 目录 04 LocalStack和Local对象实现栈的管理 1.源码入口 1. flask源码关于local的实现 2. flask源码关于l ...

  6. Flask源码关于local的实现

    flask源码关于local的实现 try: # 协程 from greenlet import getcurrent as get_ident except ImportError: try: fr ...

  7. 锁丶threading.local丶线程池丶生产者消费者模型

    一丶锁 线程安全: 线程安全能够保证多个线程同时执行时程序依旧运行正确, 而且要保证对于共享的数据,可以由多个线程存取,但是同一时刻只能有一个线程进行存取. import threading v = ...

  8. 用尽洪荒之力学习Flask源码

    WSGIapp.run()werkzeug@app.route('/')ContextLocalLocalStackLocalProxyContext CreateStack pushStack po ...

  9. Flask 源码流程,上下文管理

    源码流程 创建对象 from flask import Flask """ 1 实例化对象 app """ app = Flask(__na ...

随机推荐

  1. gitlab 6 安装备忘录

    gitlab 6.2-stable;Ubuntu 13.10;ruby 2.0.0 推荐使用PostgreSQL,MySQL不同版本可能碰到兼容性问题(www.oschina.net/question ...

  2. Atitit. 真正的全中国文字attilax易语言的特点以及范例

    Atitit. 真正的全中国文字attilax易语言的特点以及范例 1. 前言 attilax易语言是什么??1 2. attilax易语言的特点2 2.1. 支持多语言文字,不只汉字,还有藏文,维文 ...

  3. MapReduce-MulitipleOutputs实现自己定义输出到多个文件夹

    输入源数据例子: Source1-0001 Source2-0002 Source1-0003 Source2-0004 Source1-0005 Source2-0006 Source3-0007 ...

  4. NPOI读取操作excel

    .读取using (FileStream stream = new FileStream(@"c:\客户资料.xls", FileMode.Open, FileAccess.Rea ...

  5. 学习抓包之如何用Charles实现“刷楼”

    为了获取一些网络中的数据,我们需要掌握抓包技术. Charles是一个 HTTP 代理服务器, HTTP 监视器,反转代理服务器.它允许一个开发者查看所有连接互联网的 HTTP 通信.这些包括Requ ...

  6. 设置一个label显示多种颜色,多种字体大小

    UILabel* label = [[UILabel alloc] init]; label.frame = CGRectMake(0, 100, 200, 100); label.textColor ...

  7. Extjs中获取getEl获取undefined的问题

       一定注意: getEl()方法只有在panel.show()之后才会有值.在hide()的时候没有该对象.    也就是说如果要操作Ext.dom.Element对象必须让对象先显示出来.

  8. 如何解决局域网中Windows防火墙不能访问Oracle问题!

    在防火墙例外中,添加端口1521端口就样局域网内的其他机器就可以访问你的ORACLE了. 在防火墙的入站规则中,新建端口规则.过程如下例图片所示:

  9. Java并发编程(七)线程封闭

    当访问共享的可变数据时,通常需要使用同步.一种避免使用同步的方式就是不共享数据. 如果仅在单线程内访问数据,就不需要同步.这种技术被称为线程封闭(Thread Confinement),它是实现线程安 ...

  10. Swoole系列(一):简介

    前言: 实际上作为一名PHP程序员,我很清楚PHP的确有很多局限性,比如Unix系统编程.网络通信编程.异步io,大部分PHPer不懂.PHP界也确实没有这样的东西.Swoole开源项目就是为了弥补P ...