一、同步锁

1.1 多个线程抢占资源的情况

from threading import Thread
import os,time
def work():
global n
temp=n
time.sleep(0.1)
n=temp-1
if __name__ == '__main__':
n=100
l=[]
for i in range(100):
p=Thread(target=work)
l.append(p)
p.start()
for p in l:
p.join() print(n) #结果可能为99

1.1.1 对公共数据的操作

import threading
R=threading.Lock()
R.acquire()
'''
对公共数据的操作
'''
R.release()

1.2 同步锁的引用

from threading import Thread,Lock
import os,time
def work():
global n
lock.acquire()
temp=n
time.sleep(0.1)
n=temp-1
lock.release()
if __name__ == '__main__':
lock=Lock()
n=100
l=[]
for i in range(100):
p=Thread(target=work)
l.append(p)
p.start()
for p in l:
p.join() print(n) #结果肯定为0,由原来的并发执行变成串行,牺牲了执行效率保证了数据安全

1.3 互斥锁与join的区别

#不加锁:并发执行,速度快,数据不安全
from threading import current_thread,Thread,Lock
import os,time
def task():
global n
print('%s is running' %current_thread().getName())
temp=n
time.sleep(0.5)
n=temp-1 if __name__ == '__main__':
n=100
lock=Lock()
threads=[]
start_time=time.time()
for i in range(100):
t=Thread(target=task)
threads.append(t)
t.start()
for t in threads:
t.join() stop_time=time.time()
print('主:%s n:%s' %(stop_time-start_time,n)) '''
Thread-1 is running
Thread-2 is running
......
Thread-100 is running
主:0.5216062068939209 n:99
''' #不加锁:未加锁部分并发执行,加锁部分串行执行,速度慢,数据安全
from threading import current_thread,Thread,Lock
import os,time
def task():
#未加锁的代码并发运行
time.sleep(3)
print('%s start to run' %current_thread().getName())
global n
#加锁的代码串行运行
lock.acquire()
temp=n
time.sleep(0.5)
n=temp-1
lock.release() if __name__ == '__main__':
n=100
lock=Lock()
threads=[]
start_time=time.time()
for i in range(100):
t=Thread(target=task)
threads.append(t)
t.start()
for t in threads:
t.join()
stop_time=time.time()
print('主:%s n:%s' %(stop_time-start_time,n)) '''
Thread-1 is running
Thread-2 is running
......
Thread-100 is running
主:53.294203758239746 n:0
''' # 有的同学可能有疑问:既然加锁会让运行变成串行,那么我在start之后立即使用join,就不用加锁了啊,也是串行的效果啊 # 没错:在start之后立刻使用jion,肯定会将100个任务的执行变成串行,毫无疑问,最终n的结果也肯定是0,是安全的,但问题是 # start后立即join:任务内的所有代码都是串行执行的,而加锁,只是加锁的部分即修改共享数据的部分是串行的 # 单从保证数据安全方面,二者都可以实现,但很明显是加锁的效率更高.
from threading import current_thread,Thread,Lock
import os,time
def task():
time.sleep(3)
print('%s start to run' %current_thread().getName())
global n
temp=n
time.sleep(0.5)
n=temp-1 if __name__ == '__main__':
n=100
lock=Lock()
start_time=time.time()
for i in range(100):
t=Thread(target=task)
t.start()
t.join()
stop_time=time.time()
print('主:%s n:%s' %(stop_time-start_time,n)) '''
Thread-1 start to run
Thread-2 start to run
......
Thread-100 start to run
主:350.6937336921692 n:0 #耗时是多么的恐怖
''' )

二、死锁与递归锁

进程也有死锁与递归锁,在进程那里忘记说了,放到这里一起说了。

所谓死锁:是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程,如下就是死锁

2.1 死锁

from threading import Lock as Lock
import time
mutexA=Lock()
mutexA.acquire()
mutexA.acquire()
print(123)
mutexA.release()
mutexA.release()

解决方法:递归锁,在Python中为了支持在同一线程中多次请求同一资源,python提供了可重入锁RLock。

这个RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require。直到一个线程所有的acquire都被release,其他的线程才能获得资源。上面的例子如果使用RLock代替Lock,则不会发生死锁。

2.2 递归锁RLock

from threading import RLock as Lock
import time
mutexA=Lock()
mutexA.acquire()
mutexA.acquire()
print(123)
mutexA.release()
mutexA.release()

三、典型问题:科学家吃面

3.1 死锁问题

import time
from threading import Thread,Lock
noodle_lock = Lock()
fork_lock = Lock()
def eat1(name):
noodle_lock.acquire()
print('%s 抢到了面条'%name)
fork_lock.acquire()
print('%s 抢到了叉子'%name)
print('%s 吃面'%name)
fork_lock.release()
noodle_lock.release() def eat2(name):
fork_lock.acquire()
print('%s 抢到了叉子' % name)
time.sleep(1)
noodle_lock.acquire()
print('%s 抢到了面条' % name)
print('%s 吃面' % name)
noodle_lock.release()
fork_lock.release() for name in ['哪吒','nick','tank']:
t1 = Thread(target=eat1,args=(name,))
t2 = Thread(target=eat2,args=(name,))
t1.start()
t2.start()

3.2 递归锁解决死锁问题

import time
from threading import Thread,RLock
fork_lock = noodle_lock = RLock()
def eat1(name):
noodle_lock.acquire()
print('%s 抢到了面条'%name)
fork_lock.acquire()
print('%s 抢到了叉子'%name)
print('%s 吃面'%name)
fork_lock.release()
noodle_lock.release() def eat2(name):
fork_lock.acquire()
print('%s 抢到了叉子' % name)
time.sleep(1)
noodle_lock.acquire()
print('%s 抢到了面条' % name)
print('%s 吃面' % name)
noodle_lock.release()
fork_lock.release() for name in ['哪吒','nick','tank']:
t1 = Thread(target=eat1,args=(name,))
t2 = Thread(target=eat2,args=(name,))
t1.start()
t2.start()

Python程序中的线程操作-锁的更多相关文章

  1. Python程序中的线程操作(线程池)-concurrent模块

    目录 Python程序中的线程操作(线程池)-concurrent模块 一.Python标准模块--concurrent.futures 二.介绍 三.基本方法 四.ProcessPoolExecut ...

  2. 30、Python程序中的线程操作(oncurrent模块)

    进程是cpu资源分配的最小单元,一个进程中可以有多个线程. 线程是cpu计算的最小单元. 对于Python来说他的进程和线程和其他语言有差异,是有GIL锁. GIL锁 GIL锁保证一个进程中同一时刻只 ...

  3. Python程序中的线程操作-创建多线程

    目录 一.python线程模块的选择 二.threading模块 三.通过threading.Thread类创建线程 3.1 创建线程的方式一 3.2 创建线程的方式二 四.多线程与多进程 4.1 p ...

  4. Python程序中的线程操作-concurrent模块

    目录 一.Python标准模块--concurrent.futures 二.介绍 三.基本方法 四.ProcessPoolExecutor 五.ThreadPoolExecutor 六.map的用法 ...

  5. Python程序中的线程操作-守护线程

    目录 一.守护线程 1.1 详细解释 1.2 守护线程例1 1.3 守护线程例2 一.守护线程 无论是进程还是线程,都遵循:守护xx会等待主xx运行完毕后被销毁.需要强调的是:运行完毕并非终止运行. ...

  6. Python程序中的线程操作-线程队列

    目录 一.线程队列 二.先进先出 三.后进先出 四.存储数据时可设置优先级的队列 4.1 优先级队列 4.2 更多方法说明 一.线程队列 queue队列:使用import queue,用法与进程Que ...

  7. 在Python程序中的进程操作,multiprocess.Process模块

    在python程序中的进程操作 之前我们已经了解了很多进程相关的理论知识,了解进程是什么应该不再困难了,刚刚我们已经了解了,运行中的程序就是一个进程.所有的进程都是通过它的父进程来创建的.因此,运行起 ...

  8. python 全栈开发,Day38(在python程序中的进程操作,multiprocess.Process模块)

    昨日内容回顾 操作系统纸带打孔计算机批处理 —— 磁带 联机 脱机多道操作系统 —— 极大的提高了CPU的利用率 在计算机中 可以有超过一个进程 进程遇到IO的时候 切换给另外的进程使用CPU 数据隔 ...

  9. Python程序中的进程操作--—--开启多进程

    Python程序中的进程操作-----开启多进程 之前我们已经了解了很多进程相关的理论知识,了解进程是什么应该不再困难了,刚刚我们已经了解了,运行中的程序就是一个进程.所有的进程都是通过它的父进程来创 ...

随机推荐

  1. Android 下载进度对话框 ProgressDialog

    protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentV ...

  2. 监控利器-Prometheus安装与部署+实现邮箱报警

    Prometheus(普罗米修斯)监控 环境准备: 三台docker主机(centos7):docker01:172.16.1.30部署服务:Prometheus server,Grafana,Nod ...

  3. go 杂项笔记

    *** 使用go build编译该程序,注意这里需要指定 -gcflags "-N -l" 关闭编译器优化,否则编译器可能把对sum函数的调用优化掉. bobo@ubuntu:~/ ...

  4. (绿色)修正版gooflow流程解决方案(源码分享+在线演示+UI地址下载)

    gooflow出现挖矿机木马,请勿随意去其他网站下载!!! 一.功能简介 gooflow功能清单1.自定义流程绘制2.自定义属性添加3.支持3种步骤类型普通审批步骤自动决策步骤手动决策步骤 4.决策方 ...

  5. vue_04day 路由初始

    目录 vue_04 项目初始: vue 文件构造: vue项目目录结构: 项目入口(main.js): vue项目启动生命周期: 根组件(vue.js): router.js: 创建的页面: 全局样式 ...

  6. 多线程编程学习七( Fork/Join 框架).

    一.介绍 使用 java8 lambda 表达式大半年了,一直都知道底层使用的是 Fork/Join 框架,今天终于有机会来学学 Fork/Join 框架了. Fork/Join 框架是 Java 7 ...

  7. 【ST开发板评测】使用Python来开发STM32F411

    前言 板子申请了也有一段时间了,也快到评测截止时间了,想着做点有意思的东西,正好前一段时间看到过可以在MCU上移植MicroPython的示例,就自己尝试一下,记录移植过程. MicroPython是 ...

  8. SpringBoot2.0 整合 JWT 框架,解决Token跨域验证问题

    本文源码:GitHub·点这里 || GitEE·点这里 一.传统Session认证 1.认证过程 1.用户向服务器发送用户名和密码. 2.服务器验证后在当前对话(session)保存相关数据. 3. ...

  9. 通过idea将maven工程转为web项目

    前言 吐槽一下网上的各种转换教程..说的真的是吵来吵去,有用的东西极少.特此自己写一篇好使的. 转换过程 建好的maven工程 建好的maven工程长这个鬼样子~~,没有使用骨架.就是普通的建立方式. ...

  10. C#斐波那契数列求法(比较阶乘和循环所用时间)

    using System; namespace ConsoleApp3 { class Program { static void Main(string[] args) { Console.Writ ...