一、锁

  Lock(1次放1个)

    什么时候用到锁:

      线程安全,多线程操作时,内部会让所有线程排队处理。如:list、dict、queue

      线程不安全,

  1. import threading
  2. import time
  3. v = []
  4. lock = threading.Lock() #实例化了一个对象******
  5. def func(arg):
  6. lock.acquire() #加锁
  7. v.append(arg)
  8. time.sleep(0.5)
  9. m = v[-1]
  10. print(arg,m)
  11. lock.release() #加锁就要有解锁对应
  12. for i in range(1,11):
  13. t = threading.Thread(target=func,args=(i,))
  14. t.start()

  RLock(1次放1个)

    与Lock用法一致,但是RLock可以锁多次(必须有响应的解锁次数),Lock只能锁一次

  1. import threading
  2. import time
  3. v = []
  4. lock = threading.RLock()
  5. def func(arg):
  6. lock.acquire()  #锁了两次
  7. lock.acquire()
  8. v.append(arg)
  9. time.sleep(0.1)
  10. m = v[-1]
  11. print(arg,m)
  12. lock.release()  #解锁两次
  13. lock.release()
  14.  
  15. for i in range(1,11):
  16. t = threading.Thread(target=func,args=(i,))
  17. t.start()

  BoundedSemaphore(1次方固定个数个)

  1. import time
  2. import threading
  3. lock = threading.BoundedSemaphore(3) #参数是多少就一次放过去多少个线程
  4. def func(arg):
  5. lock.acquire()
  6. print(arg)
  7. time.sleep(1)
  8. lock.release()
  9. for i in range(1,11):
  10. t = threading.Thread(target=func,args=(i,))
  11. t.start()

  Condition(1次放N个)

  1. import time
  2. import threading
  3. lock = threading.Condition()
  4. def func(arg):
  5. print("start")
  6. lock.acquire()
  7. lock.wait() #****
  8. print(arg)
  9. time.sleep(1)
  10. lock.release()
  11. for i in range(1,11):
  12. t = threading.Thread(target=func,args=(i,))
  13. t.start()
  14. while 1:
  15. num = int(input(">>>>>")) #输入多少本次就会放多少个线程
  16. lock.acquire() #****
  17. lock.notify(num)
  18. lock.release() #****
  1. #也可以通过函数逻辑判断的返回值
  2. def xx():
  3. print("来执行函数了")
  4. input(">>>>")
  5. return True
  6. def func(arg):
  7. print("线程来了")
  8. lock.wait_for(xx)
  9. print(arg)
  10. time.sleep(1)
  11. for i in range(1,11):
  12. t = threading.Thread(target=func,args=(i,))
  13. t.start()

  Event(1次放所有)

  1. import threading
  2. lock = threading.Event()
  3. def func(arg):
  4. print("线程来了")
  5. lock.wait()#加锁
  6. print(arg)
  7. for i in range(1,11):
  8. t = threading.Thread(target=func,args=(i,))
  9. t.start()
  10. input(">>>>")
  11. lock.set() #解锁,如果后面不加锁上面的wait就失效了
  12. input(">>>>")
  13. lock.clear() #再次上锁
  14. for i in range(1,11):
  15. t = threading.Thread(target=func,args=(i,))
  16. t.start()
  17. input(">>>>")
  18. lock.set()

  总结:

    线程安全,列表和字典线程安全

    为什么要加锁:

      非线程安全

      控制一段代码

二、threading.local

  作用:

    内部自动为每个线程维护一个空间(字典),用于当前存取属于自己的值。保证线程之间的数据隔离

    {

      线程id:{......}

      线程id:{......}

      线程id:{......}

    }

  1. import time
  2. import threading
  3. v = threading.local()
  4. def func(arg):
  5. # 内部会为当前线程创建一个空间用于存储:phone=自己的值
  6. v.phone = arg
  7. time.sleep(1)
  8. print(v.phone,arg) # 去当前线程自己空间取值
  9. for i in range(1,11):
  10. t = threading.Thread(target=func,args=(i,))
  11. t.start()
  1. import time
  2. import threading
  3.  
  4. DATA_DICT = {}
  5.  
  6. def func(arg):
  7. ident = threading.get_ident()
  8. DATA_DICT[ident] = arg
  9. time.sleep(1)
  10. print(DATA_DICT[ident],arg)
  11.  
  12. for i in range(10):
  13. t =threading.Thread(target=func,args=(i,))
  14. t.start()

threading.local原理

  1. import time
  2. import threading
  3. INFO = {}
  4. class Local(object):
  5. def __getattr__(self, item):
  6. ident = threading.get_ident()
  7. return INFO[ident][item]
  8. def __setattr__(self, key, value):
  9. ident = threading.get_ident()
  10. if ident in INFO:
  11. INFO[ident][key] = value
  12. else:
  13. INFO[ident] = {key:value}
  14. obj = Local()
  15. def func(arg):
  16. obj.phone = arg #对象.xx="xxx" 调用了__setattr__方法
  17. time.sleep(1)
  18. print(obj.phone,arg) #对象.xx 调用了__getattr__方法
  19. for i in range(1,11):
  20. t = threading.Thread(target=func,args=(i,))
  21. t.start()

threading.local原理升级版

三、线程池

  1. from concurrent.futures import ThreadPoolExecutor
  2. import time
  3. def func(a1,a2):
  4. time.sleep(1)
  5. print(a1,a2)
  6. #创建了一个线程池(最多5个线程)
  7. pool = ThreadPoolExecutor(5)
  8. for i in range(1,21):
  9. #去线程池中申请一个线程
  10. pool.submit(func,i,"a")

四、生产者消费者模型

  三部件:

    生产者

      队列,先进先出

      栈,后进先出

    消费者

  生产者消费者模型解决了什么问题:不用一直等待的问题

  1. import time
  2. import threading
  3. import queue
  4. q = queue.Queue()#线程安全
  5. def producer(id):
  6. while 1:
  7. time.sleep(2)
  8. q.put("包子")
  9. print("厨师%s生产了一个包子"%id)
  10. for i in range(1,3):
  11. t = threading.Thread(target=producer,args=(i,))
  12. t.start()
  13. def consumer(id):
  14. while 1:
  15. time.sleep(1)
  16. q.get("包子")
  17. print("顾客%s吃了一个包子"%id)
  18. for i in range(1,4):
  19. t = threading.Thread(target=consumer,args=(i,))
  20. t.start()

示例

锁、threading.local、线程池的更多相关文章

  1. CIL锁,GIL与线程池的区别,进程池和线程池,同步与异步

    一.GIL锁 什么是GIL? 全局解释器锁,是加在解释器上的互斥锁 GC是python自带的内存管理机制,GC的工作原理:python中的内存管理使用的是应用计数,每个数会被加上一个整型的计数器,表示 ...

  2. 并发编程中死锁、递归锁、进程/线程池、协程TCP服务器并发等知识点

    1.死锁 定义; 类似两个人分别被囚禁在两间房子里,A手上拿着的是B囚禁房间的钥匙,而B拿着A的钥匙,两个人都没法出去,没法给对方开锁,进而造成死锁现象.具体例子代码如下: # -*-coding:u ...

  3. Java多线程(三)锁对象和线程池

    1:锁(Lock) 1.1       java提供了一个锁的接口,这个锁同样可以达到同步代码块的功能,API文档上说使用锁比使用synchronized更加灵活. 1.2       如何使用这个“ ...

  4. GIL锁和进程/线程池

    GIL锁 1.GIL锁 全局解释器锁,就是一个把互斥锁,将并发变成串行,同一时刻只能有一个线程使用共享资源,牺牲效率,保证数据安全,也让程序员避免自己一个个加锁,减轻开发负担 带来的问题 感觉单核处理 ...

  5. python中多进程multiprocessing、多线程threading、线程池threadpool

    浅显点理解:进程就是一个程序,里面的线程就是用来干活的,,,进程大,线程小 一.多线程threading 简单的单线程和多线程运行:一个参数时,后面要加逗号 步骤:for循环,相当于多个线程——t=t ...

  6. [Python]threading local 线程局部变量小測试

    概念 有个概念叫做线程局部变量.一般我们对多线程中的全局变量都会加锁处理,这样的变量是共享变量,每一个线程都能够读写变量,为了保持同步我们会做枷锁处理.可是有些变量初始化以后.我们仅仅想让他们在每一个 ...

  7. C#多线程和线程池 【转】

    1.概念  1.0 线程的和进程的关系以及优缺点 windows系统是一个多线程的操作系统.一个程序至少有一个进程,一个进程至少有一个线程.进程是线程的容器,一个C#客户端程序开始于一个单独的线程,C ...

  8. C#多线程和线程池

    1.概念  1.0 线程的和进程的关系以及优缺点 windows系统是一个多线程的操作系统.一个程序至少有一个进程,一个进程至少有一个线程.进程是线程的容器,一个C#客户端程序开始于一个单独的线程,C ...

  9. C#多线程和线程池[转]

    1.概念  1.0 线程的和进程的关系以及优缺点 windows系统是一个多线程的操作系统.一个程序至少有一个进程,一个进程至少有一个线程.进程是线程的容器,一个C#客户端程序开始于一个单独的线程,C ...

  10. GIL 线程池 进程池 同步 异步

    1.GIL(理论 重点)2.线程池 进程池3.同步 异步 GIL 是一个全局解释器锁,是一个互斥锁 为了防止竞争解释器资源而产生的 为何需要gil:因为一个python.exe进程中只有一份解释器,如 ...

随机推荐

  1. Docker 基础操作指南

    Docker 基础操作指南 拉取基础镜像: docker pull centos:latest 根据基础的Centos镜像运行一个名为base-centos的容器 docker run --name ...

  2. Beta冲刺(4/4)

    队名:秃头小队 组长博客 作业博客 组长徐俊杰 过去两天完成的任务:学习了很多东西 Github签入记录 接下来的计划:继续学习 还剩下哪些任务:细节处理 燃尽图 遇到的困难:自己太菜了 收获和疑问: ...

  3. Spring Boot 入门(九):集成Quartz定时任务

    本片文章续<Spring Boot 入门(八):集成RabbitMQ消息队列>,关于Quartz定时任务请参考<Quartz的基本使用之入门(2.3.0版本)> spring ...

  4. oracle如何保证数据一致性和避免脏读

      oracle通过undo保证一致性读和不发生脏读 1.不发生脏读2.一致性读3. 事务槽(ITL)小解 1.不发生脏读 例如:用户A对表更新了,没有提交,用户B对进行查询,没有提交的更新不能出现在 ...

  5. PAT(B) 1078 字符串压缩与解压(Java)

    题目链接:1078 字符串压缩与解压 (20 point(s)) 题目描述 文本压缩有很多种方法,这里我们只考虑最简单的一种:把由相同字符组成的一个连续的片段用这个字符和片段中含有这个字符的个数来表示 ...

  6. SAS学习笔记50 SAS数据集索引

    在没有索引的情况下,SAS是一条接一条的扫描观测:有索引时,直接跳到该索引对应的观测所在位置.总结一句话就是:节省时间,节省内存,提高效率 当然并不是任何情况下使用索引都能提高工作效率,因为建立索引本 ...

  7. [Luogu5320][BJOI2019]堪破神机(DP+斯特林数)

    https://www.cnblogs.com/cjyyb/p/10747543.html 特征方程+斯特林反演化简式子,要注意在模998244353意义下5没有二次剩余,所以每个数都要用$a+b\s ...

  8. apply,call和bind的使用及区别

    1.用途 1)apply,call和bind都是 用来改变this的指向 2)apply和call会让当前函数立即执行,而bind会返回一个函数,后续需要的时候再调用执行 2.this指向问题 thi ...

  9. 启动 kibana 失败

    错误信息: Sending Logstash logs to /usr/local/logstash-6.4.3/logs which is now configured via log4j2.pro ...

  10. 天梯赛 L2-024. 部落

    题解:并查集,这里要用路径压缩来优化 代码:// 这里范围理错了, 浪费20分钟debug #include <set> #include <iostream> #includ ...