标签(空格分隔): 互斥锁


进程之间的数据不共享,但是共享同一套文件系统,所以访问同一个文件,或者同一个打印终端,是没有问题的,而共享带来的问题就是竞争,竞争带来的结果就是错乱,如下:

#并发运行,效率高,但竞争同一打印终端,带来了打印错乱
from multiprocessing import Process
import os,time
def work():
print('%s is running' %os.getpid())
time.sleep(2)
print('%s is done' %os.getpid()) if __name__ == '__main__':
for i in range(3):
p=Process(target=work)
p.start()

如何控制,就是加锁处理。而互斥锁的意思就是互相排斥,如果把多个进程比喻为多个人,互斥锁的工作原理就是多个人都要去争抢同一个资源:卫生间,一个人抢到卫生间后上一把锁,其他人都要等着,等到这个完成任务后释放锁,其他人才有可能有一个抢到......所以互斥锁的原理,就是把并发改成穿行,降低了效率,但保证了数据安全不错乱

#由并发变成了串行,牺牲了运行效率,但避免了竞争
from multiprocessing import Process,Lock
import os,time
def work(lock):
lock.acquire() #加锁
print('%s is running' %os.getpid())
time.sleep(2)
print('%s is done' %os.getpid())
lock.release() #释放锁
if __name__ == '__main__':
lock=Lock()
for i in range(3):
p=Process(target=work,args=(lock,))
p.start()

模拟抢票练习:

多个进程共享同一文件,我们可以把文件当数据库,用多个进程模拟多个人执行抢票任务;

#文件db.txt的内容为:{"count":1}
#注意一定要用双引号,不然json无法识别
from multiprocessing import Process
import time,json def search(name):
dic=json.load(open('db.txt'))
time.sleep(1)
print('\033[43m%s 查到剩余票数%s\033[0m' %(name,dic['count'])) def get(name):
dic=json.load(open('db.txt'))
time.sleep(1) #模拟读数据的网络延迟
if dic['count'] >0:
dic['count']-=1
time.sleep(1) #模拟写数据的网络延迟
json.dump(dic,open('db.txt','w'))
print('\033[46m%s 购票成功\033[0m' %name) def task(name):
search(name)
get(name) if __name__ == '__main__':
for i in range(10): #模拟并发10个客户端抢票
name='<路人%s>' %i
p=Process(target=task,args=(name,))
p.start()

并发运行,效率高,但竞争写同一文件,数据写入错乱,只有一张票,卖成功给了10个人

<路人0> 查到剩余票数1

<路人1> 查到剩余票数1

<路人2> 查到剩余票数1

<路人3> 查到剩余票数1

<路人4> 查到剩余票数1

<路人5> 查到剩余票数1

<路人6> 查到剩余票数1

<路人7> 查到剩余票数1

<路人8> 查到剩余票数1

<路人9> 查到剩余票数1

<路人0> 购票成功

<路人4> 购票成功

<路人1> 购票成功

<路人5> 购票成功

<路人3> 购票成功

<路人7> 购票成功

<路人2> 购票成功

<路人6> 购票成功

<路人8> 购票成功

<路人9> 购票成功

加锁处理:购票行为由并发变成了串行,牺牲了运行效率,但保证了数据安全

#把文件db.txt的内容重置为:{"count":1}
from multiprocessing import Process,Lock
import time,json def search(name):
dic=json.load(open('db.txt'))
time.sleep(1)
print('\033[43m%s 查到剩余票数%s\033[0m' %(name,dic['count'])) def get(name):
dic=json.load(open('db.txt'))
time.sleep(1) #模拟读数据的网络延迟
if dic['count'] >0:
dic['count']-=1
time.sleep(1) #模拟写数据的网络延迟
json.dump(dic,open('db.txt','w'))
print('\033[46m%s 购票成功\033[0m' %name) def task(name,lock):
search(name)
with lock: #相当于lock.acquire(),执行完自代码块自动执行lock.release()
get(name) if __name__ == '__main__':
lock=Lock()
for i in range(10): #模拟并发10个客户端抢票
name='<路人%s>' %i
p=Process(target=task,args=(name,lock))
p.start()

执行结果:

<路人0> 查到剩余票数1

<路人1> 查到剩余票数1

<路人2> 查到剩余票数1

<路人3> 查到剩余票数1

<路人4> 查到剩余票数1

<路人5> 查到剩余票数1

<路人6> 查到剩余票数1

<路人7> 查到剩余票数1

<路人8> 查到剩余票数1

<路人9> 查到剩余票数1

<路人0> 购票成功

互斥锁与join

使用join可以将并发变成串行,互斥锁的原理也是将并发变成穿行,那我们直接使用join就可以了啊,为何还要互斥锁,说到这里我赶紧试了一下

#把文件db.txt的内容重置为:{"count":1}
from multiprocessing import Process,Lock
import time,json def search(name):
dic=json.load(open('db.txt'))
print('\033[43m%s 查到剩余票数%s\033[0m' %(name,dic['count'])) def get(name):
dic=json.load(open('db.txt'))
time.sleep(1) #模拟读数据的网络延迟
if dic['count'] >0:
dic['count']-=1
time.sleep(1) #模拟写数据的网络延迟
json.dump(dic,open('db.txt','w'))
print('\033[46m%s 购票成功\033[0m' %name) def task(name,):
search(name)
get(name) if __name__ == '__main__':
for i in range(10):
name='<路人%s>' %i
p=Process(target=task,args=(name,))
p.start()
p.join()

执行结果:

<路人0> 查到剩余票数1

<路人0> 购票成功

<路人1> 查到剩余票数0

<路人2> 查到剩余票数0

<路人3> 查到剩余票数0

<路人4> 查到剩余票数0

<路人5> 查到剩余票数0

<路人6> 查到剩余票数0

<路人7> 查到剩余票数0

<路人8> 查到剩余票数0

<路人9> 查到剩余票数0

发现使用join将并发改成穿行,确实能保证数据安全,但问题是连查票操作也变成只能一个一个人去查了,很明显大家查票时应该是并发地去查询而无需考虑数据准确与否,此时join与互斥锁的区别就显而易见了,join是将一个任务整体串行,而互斥锁的好处则是可以将一个任务中的某一段代码串行,比如只让task函数中的get任务串行

def task(name,):
search(name) # 并发执行 lock.acquire()
get(name) #串行执行
lock.release()

总结:

加锁可以保证多个进程修改同一块数据时,同一时间只能有一个任务可以进行修改,即串行地修改,没错,速度是慢了,但牺牲了速度却保证了数据安全。

虽然可以用文件共享数据实现进程间通信,但问题是:

1、效率低(共享数据基于文件,而文件是硬盘上的数据)

2、需要自己加锁处理

因此我们最好找寻一种解决方案能够兼顾:

1、效率高(多个进程共享一块内存的数据)

2、帮我们处理好锁问题。

这就是mutiprocessing模块为我们提供的基于消息的IPC通信机制:队列和管道。

队列和管道都是将数据存放于内存中,而队列又是基于(管道+锁)实现的,可以让我们从复杂的锁问题中解脱出来,因而队列才是进程间通信的最佳选择。

我们应该尽量避免使用共享数据,尽可能使用消息传递和队列,避免处理复杂的同步和锁问题,而且在进程数目增多时,往往可以获得更好的可获展性。

python网络编程之互斥锁的更多相关文章

  1. python网络编程中互斥锁与进程之间的通信

    一.互斥锁 进程之间数据隔离,但是共享一套文件系统,因而可以通过文件来实现进程直接的通信,但问题是必须自己加锁处理. 注意:加锁的目的是为了保证多个进程修改同一块数据时,同一时间只能有一个修改,即串行 ...

  2. python 并发编程 多进程 互斥锁 目录

    python 并发编程 多进程 互斥锁 模拟抢票 互斥锁与join区别

  3. python 并发编程 多进程 互斥锁与join区别

    互斥锁与join 互斥锁和join都可以把并发变成串行 以下代码是用join实现串行 from multiprocessing import Process import time import js ...

  4. python网络编程--线程递归锁RLock

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

  5. python 并发编程 多线程 互斥锁

    互斥锁 并行变成串行,牺牲效率 保证数据安全,实现局部串行 保护不同的数据,应该加不同的锁 现在一个进程 可以有多个线程 所有线程都共享进程的地址空间 实现数据共享 共享带来问题就会出现竞争 竞争就会 ...

  6. python 并发编程 多进程 互斥锁

    运行多进程  每个子进程的内存空间是互相隔离的 进程之间数据不能共享的 一 互斥锁 但是进程之间都是运行在一个操作系统上,进程之间数据不共享,但是共享同一套文件系统,所以访问同一个文件,或同一个打印终 ...

  7. python 网络编程 IO多路复用之epoll

    python网络编程——IO多路复用之epoll 1.内核EPOLL模型讲解     此部分参考http://blog.csdn.net/mango_song/article/details/4264 ...

  8. 28、Python网络编程

    一.基于TCP协议的socket套接字编程 1.套接字工作流程 先从服务器端说起.服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客 ...

  9. Python 网络编程(二)

    Python 网络编程 上一篇博客介绍了socket的基本概念以及实现了简单的TCP和UDP的客户端.服务器程序,本篇博客主要对socket编程进行更深入的讲解 一.简化版ssh实现 这是一个极其简单 ...

随机推荐

  1. mysql source 命令导入不了sql!

    sql文件也是正常, 为什么就是导入不了呢?? 后面才发现,可能是编码被notepad++ 修改了—— 一看发现是UTF-8 无BOM,改回UTF-8格式编码 就正常了!! 虽然看到的都是正常汉字, ...

  2. C# 把byte[]输出为图片文件

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/HK_JY/article/details/80320381 /// <summary> ...

  3. Redis位图实现用户签到功能

    场景需求 适用场景如签到送积分.签到领取奖励等,大致需求如下: 签到1天送1积分,连续签到2天送2积分,3天送3积分,3天以上均送3积分等. 如果连续签到中断,则重置计数,每月初重置计数. 当月签到满 ...

  4. 在keil调用Notepad++

    先打开keil, 新建一个 取名为notepad 选择notepad++的安装路径 设置参数 保持后可以看多了notepad的选项 运行当前的文件在notepad++打开

  5. Oracle表复杂查询

    转自:https://www.cnblogs.com/w-gao/p/7288293.html Oracle表复杂查询 聚合函数 max(字段值)  -- 求最大值 min(字段值)  -- 求最小值 ...

  6. delphi 连接DBF

    delphi 连接DBF 使用 DBF 文件时,文件夹表示数据库,单个 DBF 文件表示表 1.BDE,已淘汰 table1.Databasename:=dbdir;//设置库路径table1.Tab ...

  7. jeecg好用吗,看看大家的评价

    大家都会有个疑问,jeecg好用吗? 看看大家的评价

  8. python字符串查找

    a = "string test" a.index("g") a.find("g")

  9. Java读写avro例子

    一.avro是一个数据序列化框架,可以高效得进行序列化和反序列化,支持C, C++, C#, Java, PHP, Python, 和Ruby语言.现在使用Java来读写. 二.环境搭建 1.下载av ...

  10. 什么是socket?

    1.七层协议简化为四层:应用层.传输层.网络层.链路层:2.套接字是应用层和TCP/IP协议族通信间的软件抽象层,将TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用实现进程在网络中的通信:本地 ...