zoukankan      html  css  js  c++  java
  • 38_并发编程-锁

    一、定义
     
      我们千方百计实现了程序的异步,让多个任务可以同时在几个进程中并发处理,他们之间的运行没有顺序,一旦开启也不受我们控制。尽管并发编程让我们能更加充分的利用IO资源,但是也给我们带来了新的问题:进程之间数据不共享,但是共享同一套文件系统,所以访问同一个文件,或同一个打印终端,是没有问题的,而共享带来的是竞争,竞争带来的结果就是错乱,如何控制,就是加锁处理。
     
      1、 多进程抢占输出资源
     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()
    多进程

      2、 使用锁维护执行顺序

     1 # 由并发变成了串行,牺牲了运行效率,但避免了竞争
     2 import os
     3 import time
     4 import random
     5 from multiprocessing import Process,Lock
     6 
     7 def work(lock,n):
     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 if __name__ == '__main__':
    14     lock=Lock()
    15     for i in range(3):
    16         p=Process(target=work,args=(lock,i))
    17         p.start()
    使用锁维护秩序顺序

    二、抢票系统

     1 #注意:首先在当前文件目录下创建一个名为db的文件
     2 #文件db的内容为:{"count":1},只有这一行数据,并且注意,每次运行完了之后,文件中的1变成了0,你需要手动将0改为1,然后在去运行代码。
     3 #注意一定要用双引号,不然json无法识别
     4 #加锁保证数据安全,不出现混乱
     5 from multiprocessing import Process,Lock
     6 import time,json,random
     7 
     8 #查看剩余票数
     9 def search():
    10     dic=json.load(open('db')) #打开文件,直接load文件中的内容,拿到文件中的包含剩余票数的字典
    11     print('33[43m剩余票数%s33[0m' %dic['count'])
    12 
    13 #抢票
    14 def get():
    15     dic=json.load(open('db'))
    16     time.sleep(0.1)       #模拟读数据的网络延迟,那么进程之间的切换,导致所有人拿到的字典都是{"count": 1},也就是每个人都拿到了这一票。
    17     if dic['count'] >0:
    18         dic['count']-=1
    19         time.sleep(0.2)   #模拟写数据的网络延迟
    20         json.dump(dic,open('db','w'))
    21         #最终结果导致,每个人显示都抢到了票,这就出现了问题~
    22         print('33[43m购票成功33[0m')
    23     else:
    24         print('sorry,没票了亲!')
    25 def task(lock):
    26     search()
    27     #因为抢票的时候是发生数据变化的时候,所有我们将锁加加到这里
    28     lock.acquire()
    29     get()
    30     lock.release()
    31 if __name__ == '__main__':
    32     lock = Lock() #创建一个锁
    33     for i in range(3): #模拟并发100个客户端抢票
    34         p=Process(target=task,args=(lock,)) #将锁作为参数传给task函数
    35         p.start()
    36 
    37 #看结果分析:只有一个人抢到了票
    38 # 剩余票数1
    39 # 剩余票数1
    40 # 剩余票数1
    41 # 购票成功   #幸运的人儿
    42 # sorry,没票了亲!
    43 # sorry,没票了亲!
    44 
    45 加锁:购票行为由并发变成了串行,牺牲了效率,但是保证了数据安全
    抢票系统

    三、总结

      1、加锁可以保证多个进程修改同一块数据时,同一时间只能有一个任务可以进行修改,即串行的修改,没错,速度是慢了,但牺牲了速度却保证了数据安全。
    虽然可以用文件共享数据实现进程间通信,但问题是:
      <1>.效率低(共享数据基于文件,而文件是硬盘上的数据)
      <2>.需要自己加锁处理
     
      2、因此我们最好找寻一种解决方案能够兼顾:1、效率高(多个进程共享一块内存的数据)2、帮我们处理好锁问题。这就是mutiprocessing模块为我们提供的基于消息的IPC通信机制:队列和管道。
      3、队列和管道都是将数据存放于内存中,队列又是基于(管道+锁)实现的,可以让我们从复杂的锁问题中解脱出来,我们应该尽量避免使用共享数据,尽可能使用消息传递和队列,避免处理复杂的同步和锁问题,而且在进程数目增多时,往往可以获得更好的可获展性。
      4、IPC通信机制(了解):IPC是intent-Process Communication的缩写,含义为进程间通信或者跨进程通信,是指两个进程之间进行数据交换的过程。IPC不是某个系统所独有的,任何一个操作系统都需要有相应的IPC机制,
    比如Windows上可以通过剪贴板、管道和邮槽等来进行进程间通信,而Linux上可以通过命名共享内容、信号量等来进行进程间通信。Android它也有自己的进程间通信方式,Android建构在Linux基础上,继承了一部分Linux的通信方式。

     

  • 相关阅读:
    OSG-提示“error reading file e:1.jpg file not handled”
    OSG-加载地球文件报0x00000005错误,提示error reading file simple.earth file not handled
    QT-找开工程后,最上方提示the code model could not parse an included file, which might lead to incorrect code completion and highlighting, for example.
    我的书《Unity3D动作游戏开发实战》出版了
    java中无符号类型的第三方库jOOU
    Windows批处理备份mysql数据
    使用 DevTools 时,通用Mapper经常会出现 class x.x.A cannot be cast to x.x.A
    Java版本,Java版本MongoDB驱动,驱动与MongoDB数据库,Spring之间的兼容性
    Jrebel本地激活方法
    wget下载指定网站目录下的所有内容
  • 原文地址:https://www.cnblogs.com/hq82/p/9851570.html
Copyright © 2011-2022 走看看