进程互斥锁

进程之间数据不共享,但是共享同一套文件系统,所以访问同一个文件,或同一个打印终端,是没有问题的,

竞争带来的结果就是错乱,如何控制,就是加锁处理

part1:多个进程共享同一打印终端

from multiprocessing import Process,Lock
import os,time,random

def task(mutex):
    mutex.acquire()
    print('%s print 1' %os.getpid())
    time.sleep(random.randint(1,3))
    print('%s print 2' %os.getpid())
    time.sleep(random.randint(1,3))
    print('%s print 3' %os.getpid())
    mutex.release()

if __name__ == '__main__':
    mutex=Lock()
    p1=Process(target=task,args=(mutex,))
    p2=Process(target=task,args=(mutex,))
    p3=Process(target=task,args=(mutex,))
    p1.start()
    p2.start()
    p3.start()
由并发变成了串行,牺牲了运行效率,但避免了竞争
加锁可以保证多个进程修改同一块数据时,同一时间只能有一个任务可以进行修改,即串行的修改,没错,速度是慢了,但牺牲了速度却保证了数据安全。
虽然可以用文件共享数据实现进程间通信,缺点:
1.效率低(共享数据基于文件,而文件是硬盘上的数据)
2.需要自己加锁处理


线程互斥锁
join是等待所有,即整体串行,而锁只是锁住修改共享数据的部分,即部分串行,要想保证数据安全的根本原理在于让并发变成串行,join与互斥锁都可以实现,毫无疑问,互斥锁的部分串行效率要更高
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
锁通常被用来实现对共享资源的同步访问。为每一个共享资源创建一个Lock对象,当你需要访问该资源时,调用acquire方法来获取锁对象(如果其它线程已经获得了该锁,则当前线程需等待其被释放),待资源访问完后,再调用release方法释放锁:
from threading import Thread,Lock
import time
n=100
def task():
    # global n
    # mutex.acquire()
    # temp=n
    # time.sleep(0.1)
    # n=temp-1
    # mutex.release()
    global n
    with mutex:
        temp=n
        time.sleep(0.1)
        n=temp-1
if __name__ == '__main__':
    mutex=Lock()
    t_l=[]
    for i in range(100):
        t=Thread(target=task)
        t_l.append(t)
        t.start()
    for t in t_l:
        t.join()
    print(n)    
#结果为0,由原来的并发执行变成串行,牺牲了执行效率保证了数据安全

互斥锁和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 #耗时是多么的恐怖
'''
复制代码
互斥锁和join的区别

 

模拟抢票
db.txt文件内容:{"count":1}
from  multiprocessing import Process,Lock
import json
import os
import time
import random
def search():
    with open("db.txt",encoding="utf-8") as f:
        dic=json.load(f)
        print('%s 剩余票数 %s' % (os.getpid(), dic['count']))
def get():
    with open("db.txt",encoding="utf-8") as read_f:
        dic=json.load(read_f)
    if dic["count"]>0:
        dic["count"] -= 1
        time.sleep(random.randint(1, 3))
        with open("db.txt","w",encoding="utf-8") as write_f:
            json.dump(dic,write_f)
            print('%s 抢票成功' %os.getpid())
def task(mutex):
    search()
    mutex.acquire()
    get()
    mutex.release()
if __name__ == "__main__":
    mutex = Lock()
    for i in range(20):
        p = Process(target=task,args=(mutex,))
        p.start()

 



 

 

posted on 2017-12-04 16:34  Py行僧  阅读(447)  评论(0编辑  收藏  举报