同步锁

import  time, threading

def addNum():
global num
num -= 1 num = 100 thread_list = []
for i in range(100):
t = threading.Thread(target=addNum)
t.start()
thread_list.append(t) for t in thread_list:
t.join() print('final num:', num) 运行结果:
final num: 0
import  time, threading

def addNum():
global num
#num -= 1
tmp = num
time.sleep(0.00001)
num = tmp - 1 num = 100 thread_list = []
for i in range(100):
t = threading.Thread(target=addNum)
t.start()
thread_list.append(t) for t in thread_list:
t.join() print('final num:', num) 运行结果:
final num: 93

final num: 91

final num: 94

原因:

第一个程序中,num -= 1 这种写法,程序执行动作太快(完成这个动作在 cup 切换的时间内)

第二个程序中,把 num -= 1 , 加入了 sleep 时间,100个线程存在没有执行完就进行了切换,导致全局的 num 没有正常返回。引用下大神的图发现总结得非常好:



在上面的例子中 使用 join 方法会把整个线程停住,造成了串行,失去了多线程的意义,我们只需要在涉及到计算公共数据的时候串行执行即可。

使用同步锁处理计算公共的数据

import  time, threading

def addNum():
global num lock.acquire()
tmp = num
time.sleep(0.00001)
num = tmp - 1
lock.release() num = 100
lock = threading.Lock()
thread_list = []
for i in range(100):
t = threading.Thread(target=addNum)
t.start()
thread_list.append(t) for t in thread_list:
t.join() print('final num:', num) 运算结果:
final num: 0

线程死锁和递归锁

import  threading, time

class myThread(threading.Thread):
def doA(self):
lockA.acquire()
print(self.name, "gotlockA", time.ctime())
time.sleep(3)
lockB.acquire()
print(self.name, "gotlockB", time.ctime())
lockB.release()
lockA.release() def doB(self):
lockB.acquire()
print(self.name, "gotlockB", time.ctime())
time.sleep(2)
lockA.acquire()
print(self.name, "gotlockA", time.ctime())
lockA.release()
lockB.release() def run(self):
self.doA()
self.doB() if __name__ == '__main__':
lockA = threading.Lock()
lockB = threading.Lock()
threads = []
for i in range(5):
threads.append(myThread())
for t in threads:
t.start()
for t in threads:
t.join() #运行结果:
Thread-1 gotlockA Sat Jul 28 15:09:31 2018
Thread-1 gotlockB Sat Jul 28 15:09:34 2018
Thread-1 gotlockB Sat Jul 28 15:09:34 2018
Thread-2 gotlockA Sat Jul 28 15:09:34 2018

使用递归锁

import  threading, time

class myThread(threading.Thread):
def doA(self):
lock.acquire()
print(self.name, "gotlockA", time.ctime())
time.sleep(3)
lock.acquire()
print(self.name, "gotlockB", time.ctime())
lock.release()
lock.release() def doB(self):
lock.acquire()
print(self.name, "gotlockB", time.ctime())
time.sleep(2)
lock.acquire()
print(self.name, "gotlockA", time.ctime())
lock.release()
lock.release() def run(self):
self.doA()
self.doB() if __name__ == '__main__':
lock = threading.RLock()
threads = []
for i in range(5):
threads.append(myThread())
for t in threads:
t.start()
for t in threads:
t.join() 运行结果:
Thread-1 gotlockA Sat Jul 28 15:19:35 2018
Thread-1 gotlockB Sat Jul 28 15:19:38 2018
Thread-1 gotlockB Sat Jul 28 15:19:38 2018
Thread-1 gotlockA Sat Jul 28 15:19:40 2018
Thread-3 gotlockA Sat Jul 28 15:19:40 2018
Thread-3 gotlockB Sat Jul 28 15:19:43 2018
Thread-3 gotlockB Sat Jul 28 15:19:43 2018
Thread-3 gotlockA Sat Jul 28 15:19:45 2018
Thread-5 gotlockA Sat Jul 28 15:19:45 2018
Thread-5 gotlockB Sat Jul 28 15:19:48 2018
Thread-5 gotlockB Sat Jul 28 15:19:48 2018
Thread-5 gotlockA Sat Jul 28 15:19:50 2018
Thread-4 gotlockA Sat Jul 28 15:19:50 2018
Thread-4 gotlockB Sat Jul 28 15:19:53 2018
Thread-4 gotlockB Sat Jul 28 15:19:53 2018
Thread-4 gotlockA Sat Jul 28 15:19:55 2018
Thread-2 gotlockA Sat Jul 28 15:19:55 2018
Thread-2 gotlockB Sat Jul 28 15:19:58 2018
Thread-2 gotlockB Sat Jul 28 15:19:58 2018
Thread-2 gotlockA Sat Jul 28 15:20:00 2018

信号量

信号量用来控制线程并发数的,BoundedSemaphore或Semaphore管理一个内置的计数 器,每当调用acquire()时-1,调用release()时+1,计数器不能小于0,当计数器为 0时,acquire()将阻塞线程至同步锁定状态,直到其他线程调用release()。(类似于停车位的概念)。

BoundedSemaphore与Semaphore的唯一区别在于前者将在调用release()时检查计数 器的值是否超过了计数器的初始值,如果超过了将抛出一个异常。

import threading, time

class myThread(threading.Thread):
def run(self):
if semaphore.acquire():
print(self.name)
time.sleep(5)
semaphore.release() if __name__ == "__main__":
semaphore = threading.Semaphore(5)
thrs = []
for i in range(20):
thrs.append(myThread())
for t in thrs:
t.start() #运行结果:
Thread-1
Thread-2
Thread-3
Thread-4
Thread-5
Thread-6
Thread-7
Thread-9
Thread-10
Thread-8
Thread-11
Thread-13
Thread-14
Thread-12
Thread-15
Thread-18
Thread-16
Thread-17
Thread-19
Thread-20
import threading, time

class myThread(threading.Thread):
def run(self):
if semaphore.acquire():
print(self.name)
time.sleep(5)
semaphore.release() if __name__ == "__main__":
semaphore = threading.BoundedSemaphore(5)
thrs = []
for i in range(20):
thrs.append(myThread())
for t in thrs:
t.start() #运行结果:
Thread-1
Thread-2
Thread-3
Thread-4
Thread-5
Thread-6
Thread-8
Thread-10
Thread-9
Thread-7
Thread-12
Thread-14
Thread-15
Thread-13
Thread-11
Thread-16
Thread-17
Thread-20
Thread-19
Thread-18

Python 线程同步锁, 信号量的更多相关文章

  1. Python之路(第四十四篇)线程同步锁、死锁、递归锁、信号量

    在使用多线程的应用下,如何保证线程安全,以及线程之间的同步,或者访问共享变量等问题是十分棘手的问题,也是使用多线程下面临的问题,如果处理不好,会带来较严重的后果,使用python多线程中提供Lock ...

  2. python线程同步原语--源码阅读

    前面两篇文章,写了python线程同步原语的基本应用.下面这篇文章主要是通过阅读源码来了解这几个类的内部原理和是怎么协同一起工作来实现python多线程的. 相关文章链接:python同步原语--线程 ...

  3. python线程互斥锁Lock(29)

    在前一篇文章 python线程创建和传参 中我们介绍了关于python线程的一些简单函数使用和线程的参数传递,使用多线程可以同时执行多个任务,提高开发效率,但是在实际开发中往往我们会碰到线程同步问题, ...

  4. 第十五章、Python多线程同步锁,死锁和递归锁

    目录 第十五章.Python多线程同步锁,死锁和递归锁 1. 引子: 2.同步锁 3.死锁 引子: 4.递归锁RLock 原理: 不多说,放代码 总结: 5. 大总结 第十五章.Python多线程同步 ...

  5. Python并发编程-进程 线程 同步锁 线程死锁和递归锁

    进程是最小的资源单位,线程是最小的执行单位 一.进程 进程:就是一个程序在一个数据集上的一次动态执行过程. 进程由三部分组成: 1.程序:我们编写的程序用来描述进程要完成哪些功能以及如何完成 2.数据 ...

  6. Python并行编程(五):线程同步之信号量

    1.基本概念 信号量是由操作系统管理的一种抽象数据类型,用于在多线程中同步对共享资源的使用.本质上说,信号量是一个内部数据,用于标明当前的共享资源可以有多少并发读取. 同样在threading中,信号 ...

  7. Python线程同步

    线程执行 join与setDaemon 子线程在主线程运行结束后,会继续执行完,如果给子线程设置为守护线程(setDaemon=True),主线程运行结束子线程即结束: 如果join()线程,那么主线 ...

  8. Python3 进程 线程 同步锁 线程死锁和递归锁

    进程是最小的资源单位,线程是最小的执行单位 一.进程 进程:就是一个程序在一个数据集上的一次动态执行过程. 进程由三部分组成: 1.程序:我们编写的程序用来描述进程要完成哪些功能以及如何完成 2.数据 ...

  9. 线程同步、信号量、system v IPC

    一.线程同步 条件变量 什么是条件变量? 线程A等待某个条件成立,条件成立,线程A才继续向下执行.线程B的执行使条件成立,条件成立以后唤醒线程A,以继续执行.这个条件就是条件变量. pthread_c ...

随机推荐

  1. git 删除本地分支、远程分支、本地回滚、远程回滚

    一. git 删除分支 1. git 删除本地分支 git branch -D branchname 2. git 删除远程分支 git push origin :branchname (origin ...

  2. 使用CGlib出现java.lang.NoClassDefFoundError: org/objectweb/asm/Type异常

    在学习使用CGlib生成动态代理对象,项目的源代码也很简单: package proxy; import java.lang.reflect.Method; import net.sf.cglib.p ...

  3. PICE(6):集群环境里多异类端点gRPC Streaming - Heterogeneous multi-endpoints gRPC streaming

    gRPC Streaming的操作对象由服务端和客户端组成.在一个包含了多个不同服务的集群环境中可能需要从一个服务里调用另一个服务端提供的服务.这时调用服务端又成为了提供服务端的客户端了(服务消费端) ...

  4. Tools - Vim

    Vim 简明 Vim 练级攻略 基础设置 在vim界面点击":"然后进行设置,但只会在当前vim界面生效: 添加相关设置在vim配置文件(例如"/etc/vimrc&qu ...

  5. Ubuntu 18.0.4安装docker

    第一步:如果之前安装过docker,执行下面命令删除 apt-get remove docker docker-engine docker.io 删除后执行sudo apt-get update更新软 ...

  6. javascript实现二分法

    js 实现数组查找二分法 二分法实现原理:二分查找可以解决已经排好序数组的查找问题:只要数组中包含target(即要查找的值),那么通过不断缩小包含target数组的范围,最终就可以找到它. 其算法流 ...

  7. Spring 源码分析之 bean 依赖注入原理(注入属性)

         最近在研究Spring bean 生命周期相关知识点以及源码,所以打算写一篇 Spring bean生命周期相关的文章,但是整理过程中发现涉及的点太多而且又很复杂,很难在一篇文章中把Spri ...

  8. go微服务框架go-micro深度学习 rpc方法调用过程详解

    摘要: 上一篇帖子go微服务框架go-micro深度学习(三) Registry服务的注册和发现详细解释了go-micro是如何做服务注册和发现在,服务端注册server信息,client获取serv ...

  9. oracle中常见的对表、表空间和视图的操作

    创建表:create table t1(key1 type default 0,key2 type not null) 删除表:drop table t1; 删除表数据:truncate table ...

  10. 使用Charles抓取APP之HTTPS请求

    Charles是一款非常好用的抓包工具,通常使用它来进行APP开发抓包调试,尤其是HTTPS请求. 一.安装Charles 去官网(https://www.charlesproxy.com/)下载软件 ...