博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Part 4系统编程之进程---进程同步
阅读量:6850 次
发布时间:2019-06-26

本文共 3612 字,大约阅读时间需要 12 分钟。

(一)简介

通过之前的学习,我们千方百计实现了程序的异步,让多个任务可以同时在几个进程中并发处理,他们之间的运行没有顺序,一旦开启也不受我们控制。尽管并发编程让我们能更加充分的利用IO资源,但是也给我们带来了新的问题:当多个进程使用同一份数据资源的时候,就会引发数据安全或顺序混乱问题。例如下列情形--多进程抢占输出资源:

1 import os 2 import time 3 import random 4 from multiprocessing import Process 5   6 def work(n): 7     print('%s: %s is running' %(n,os.getpid())) 8     time.sleep(random.random()) 9     print('%s:%s is done' %(n,os.getpid()))10  11 if __name__ == '__main__':12     for i in range(3):13         p=Process(target=work,args=(i,))14         p.start()15 16 17 》》》输出:18 1: 16548 is running19 0: 1448 is running20 2: 1096 is running21 2:1096 is done22 0:1448 is done23 1:16548 is done

可以看到我们的输出结果是乱的,如果想有序的执行,先run再done,怎么办?

 这时,就要用到我们今天的内容,锁!

(二)创建锁

首先我们要引入Lock,接着在进程开始和结束分别给取得锁和释放锁,代码如下:

1 import os 2 import time 3 import random 4 from multiprocessing import Lock 5 from multiprocessing import Process 6   7 def work(n,lock): 8     lock.acquire()  #取得锁 9     print('%s: %s is running' %(n,os.getpid()))10     time.sleep(random.random())11     print('%s:%s is done' %(n,os.getpid()))12     lock.release()  #释放锁13  14 if __name__ == '__main__':15     lock = Lock()  #创建锁16     for i in range(5):17         p=Process(target=work,args=(i,lock))18         p.start()19 20 21 》》》输出:22 0: 17468 is running23 0:17468 is done24 2: 16688 is running25 2:16688 is done26 1: 15984 is running27 1:15984 is done28 3: 15828 is running29 3:15828 is done30 4: 18156 is running31 4:18156 is done

从结果上看,每个进程都是先开始再结束,尽管进程执行的顺序是无序的

(三)锁的原理

我们用下图来解释:

 

理论上来讲,进程一般是异步的

但是加了锁之后,就变成同步

但进程执行的顺序为什么是无序的呢?这就要看谁先拿到钥匙了,优先者满足以下2个条件:

1.操作系统先响应的进程
2.当时没有时间片轮询,刚好就是它

那如何做到有序执行进程呢?就用之前说的join,他会阻塞进程,使进程串行执行。

1 import os 2 import time 3 import random 4 from multiprocessing import Process 5   6 def work(n): 7     print('%s: %s is running' %(n,os.getpid())) 8     time.sleep(random.random()) 9     print('%s:%s is done' %(n,os.getpid()))10  11 if __name__ == '__main__':12     for i in range(5):13         p=Process(target=work,args=(i,))14         p.start()15         p.join()16 17 18 》》》输出:19 0: 17348 is running20 0:17348 is done21 1: 18164 is running22 1:18164 is done23 2: 18160 is running24 2:18160 is done25 3: 17652 is running26 3:17652 is done27 4: 8340 is running28 4:8340 is done

所以我们从结果可以看到锁和join的区别就在于此:

锁执行时是无序的,join是有序的

由并发变成了串行,牺牲了运行效率,但避免了竞争,却保证了数据的安全。

 (四)实例演示

总结一下之前的内容:

同步控制:

只要用到了锁 锁之间的代码就会变成同步的

锁 :控制一段代码 同一时间 只能被一个进程执行

 接下来,我们简单演示一下12306抢票中锁的应用,我们知道抢票分为一下几步:

用户发送买票请求》》收到请求后在数据库读取数据》》如果还有票就在数据库减少一张票》》告知用户抢票成功

 我们在代码中会模拟两次延时,分别是读取延时和写入延时,这是因为服务器和数据库不在同一台机器上,他们之间交互数据,必然有延时。

代码如下:

1 import time 2 import random 3 from multiprocessing import Process 4 from multiprocessing import Lock 5 import json 6  7  8 def buy_ticket(i, lock): 9     #取得锁保证数据共享的单一性,避免错误10     lock.acquire()11     #读取文件12     with open('ticket') as f:13         #反序列化,将字符串转换为字典14         tick_count = json.load(f)15         #模拟读取延时16         time.sleep(random.random())17     #判断余票并进行相应操作18     if tick_count['count'] > 0:19         print('person%s购票成功'%i)20         tick_count['count'] -= 121     else:22         print('余票不足,person%s购票失败'%i)23     #将信息写入文件24     with open('ticket', 'w') as f:25         json.dump(tick_count,f)26         #模拟写入延时27         time.sleep(random.random())28     #释放锁29     lock.release()30 31 32 if __name__ == '__main__':33     lock = Lock()  #创建锁34     for i in range(5):  # 模拟5个用户抢票35         Process(target=buy_ticket, args=(i, lock)).start()36 37 》》》输出:38 person0购票成功39 余票不足,person1购票失败40 余票不足,person2购票失败41 余票不足,person3购票失败42 余票不足,person4购票失败
加锁可以保证多个进程修改同一块数据时,同一时间只能有一个任务可以进行修改,即串行的修改,没错,速度是慢了,但牺牲了速度却保证了数据安全。

 

转载于:https://www.cnblogs.com/boru-computer/p/9737252.html

你可能感兴趣的文章
程序员有五种错误不应犯
查看>>
无线认证知识点
查看>>
基于python的REST框架eve测试与mongodb的数据操作
查看>>
epoll模型的理解封装与应用
查看>>
Lync 2013部署图片赏析-证书服务安装配置
查看>>
HTML5 本地缓存 (web存储)
查看>>
tomcat redis session共享(包含redis安全设置)
查看>>
iptables中DNAT、SNAT和MASQUERADE的作用
查看>>
kvm命令学习记录
查看>>
小菜鸡进阶之路-First week
查看>>
ORACLE 10g SYSAUX表空间快速增长之WRH$_ACTIVE_SESSION_HISTORY篇
查看>>
我的友情链接
查看>>
我的友情链接
查看>>
mybatis大数据提交和更新,数据SQL语句批量提交数据库
查看>>
每天一个小算法(Shell Sort2)
查看>>
Java数据结构与算法(7) - ch05双向链表(Double List)
查看>>
自适应布局
查看>>
L2-015. 互评成绩
查看>>
poj3186 poj3267
查看>>
L365
查看>>