一、介绍为什么要用进程锁

我们首先看一个例子:

Value 是一个内存共享模块,即使得主进程和子进程共享一块内存…
关于Value共享整数或者单个字符,用 Value(‘i’, 1), Value(‘c’, ‘1’)即可。
如果要是共享字符串,则要导入如下,用 Value(c_char_p, ‘xxx’)即可。

from ctypes import c_char_p

下面先看一个例子,银行存取钱的程序,生活中,取钱与存钱如果要是同时在两个ATM机操作,那么会带来怎样的结果,比如银行卡有一完块钱,两个人同时操作,一个人取九千块,一个人存一万块,那么结果究竟是怎样的呢,然而,现实是存取钱是不可能让两个进程同时操纵数据,否则会带来数据的混乱,下面从这个小例子来解释:

from multiprocessing import Process,Value,Lock
import time

def get_money(num):#取钱
    for i in range(100):#取一百块钱
        num.value -= 1
        time.sleep(0.01)


def save_money(num):#存钱
    for i in range(100):#存一百块钱
        num.value += 1
        time.sleep(0.01)

if __name__ == '__main__':
    num = Value('i',100)#内存共享,主进程和子进程内存共享
    p = Process(target=get_money,args=(num,L))
    p.start()
    p_1 = Process(target=save_money,args=(num,L))
    p_1.start()
    p.join()
    p_1.join()
    print(num.value)

结果运行一下会发现,结果是不固定的,那么究竟是怎么回事呢?
原来我们同时开启了两个进程,一个进行取钱操作,一个进行存钱操作,操作的数据是同一个数据num,两个进程都要被CPU光顾才能进行操作,而这两个进程的执行是依靠时间片轮转来轮流操作,而CPU内部执行如下赋值语句并不是这么简单

i = 3
i += 1

而是通过

tmp = i 【1】
tmp = tmp + 1 【2】
i = tmp 【3】

所以当某次程序执行到i = 199【1】时,tmp = 200【2】,时间片用完了,转到另一个取钱进程,假如取钱进程只执行了一次使得i = 198,时间片刚好用完,转到存钱进程,继续上次没有完成的操作,i = tmp = 200【3】 那么就将夹在其中的取钱进程给覆盖掉了。
所以为了防止共享内存导致的数据混乱,所以要用进程锁,但也必然会带来效率的降低。
进程锁加上如下:

from multiprocessing import Process,Value,Lock
import time

def get_money(num,L):
   L.acquire()
   for i in range(100):
       num.value -= 1
       time.sleep(0.01)
   L.release()

def save_money(num,L):
   L.acquire()
   for i in range(100):
       num.value += 1
       time.sleep(0.01)
   L.release()

if __name__ == '__main__':
   num = Value('i',100)
   L = Lock()
   p = Process(target=get_money,args=(num,L))
   p.start()
   p_1 = Process(target=save_money,args=(num,L))
   p_1.start()
   p.join()
   p_1.join()
   print(num.value)

还可以看一个抢票的小程序:

from multiprocessing import Process,Lock
import time
def check(i,l):
    l.acquire()#拿钥匙
    with open('余票') as f:
        con = f.read()
    print('余票还有{}'.format(con))
    l.release()#还钥匙
def buy_ticket(i,l):
    l.acquire()
    with open('余票') as f:
        con = int(f.read())
    if con > 0:
        print('\033[31m 第{}个人买到票了\033[0m'.format(i))
        con -= 1
    else:
        print('\033[32m 第{}个人没有买到票\033[0m'.format(i))
    with open('余票','w') as f :
        f.write(str(con))
    l.release()
if __name__ == '__main__':
    l = Lock()
    for i in range(10):
        p_ch = Process(target=check,args=(i+1,l))
        p_ch.start()
    for i in range(10):
        p_buy = Process(target=buy_ticket,args=(i+1,l))
        p_buy.start()

二、进程锁只能拿钥匙开锁,还钥匙加锁,有没有可以多配几把钥匙的方法,下面介绍信号机制

开启20个子进程,一次性只有三个进程能运行函数func ,sem.acquire() 是拿上钥匙,sem.release()是还钥匙 拿上钥匙开锁,还钥匙后别的进程才能进入。

import time
import random
from multiprocessing import Process
def func(i,sem):
    sem.acquire()
    print('\033[31m第{}进入小黑屋,拿了钥匙锁上门\033[0m'.format(i))
    time.sleep(random.randint(1,5))
    print('第{}个人出去了小黑屋,还了钥匙上门'.format(i))
    sem.release()
if __name__ =='__main__':
    sem = Semaphore(3)#初始化几把钥匙
    for i in range(20):
        p = Process(target= func,args=(i,sem))
        p.start()

比如第一次进程1,2,4执行程序,接着3,7,9执行…

python共享内存 windown python共享内存 value_数据

三、那有没有根据事件进行开关锁的呢,也是有的。

关于Event 模块的使用如下:

from multiprocessing import Event
e = Event()
事件是通过is_set()的bool值,去标识e.wait()的阻塞状态
当is_set()的bool值为False时,e.wait()是阻塞状态
当is_set()的bool值为True时,e.wait()是非阻塞状态
当使用set()时,是把is_set的bool值变为True
当使用clear()时,是把is_set的bool值变为False

下面介绍一下信号灯程序:

from multiprocessing import Event,Process
import time
def traffic(e):
    '''信号灯'''
    while 1:
        if e.is_set():
            time.sleep(5)
            print('\033[33m 红灯亮!\033[0m ')
            e.clear()
        else:
            time.sleep(5)
            print('\033[32m 绿灯亮!\033[0m')
            e.set()

def Car(i,e):
    e.wait()
    print('第{}辆车经过!'.format(i))
if __name__== '__main__':
    e = Event()
    triff_light = Process(target=traffic,args=(e,))
    triff_light.start()
    for i in range(50):
        car = Process(target=Car,args=(i+1,e))
        car.start()

下图是上段程序的图解:

python共享内存 windown python共享内存 value_数据_02


最后,分享知识,造福人民,为实现我们中华民族伟大复兴!祝大家越来越好!