浅谈线程锁和进程锁

​ 在python的多线程和多进程中,当我们需要对多线程或多进程的共享资源或对象进行修改操作时,往往会出现因cpu随机调度而导致结果和我们预期不一致的问题,

线程举例:

from threading import Thread,Lock

x = 0
def task():
    global x
    for i in range(200000):
        x = x+1
'''
假设
t1 的 x刚拿到0 保存状态 就被切了
t2 的 x拿到0 进行+1       1
t1 又获得运行了  x = 0  +1  1
思考:一共加了几次1? 加了两次1 真实运算出来的数字本来应该+2 实际只+1
这就产生了数据安全问题.
'''        


if __name__ == '__main__':
    t1 = Thread(target=task)
    t2 = Thread(target=task)
    t3 = Thread(target=task)
    t1.start()
    t2.start()
    t3.start()
    t1.join()
    t2.join()
    t3.join()
    print(x)

479261

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

def search():
    time.sleep(1) # 模拟网络io
    with open('db.txt',mode='rt',encoding='utf-8') as f:
        res = json.load(f)
        print(f'还剩{res["count"]}')

def get():
    with open('db.txt',mode='rt',encoding='utf-8') as f:
        res = json.load(f)
    time.sleep(1) # 模拟网络io
    if res['count'] > 0:
        res['count'] -= 1
        with open('db.txt',mode='wt',encoding='utf-8') as f:
            json.dump(res,f)
            print(f'进程{os.getpid()} 抢票成功')
        time.sleep(1.5) # 模拟网络io
    else:
        print('票已经售空啦!!!!!!!!!!!')

def task():
    search()
    get()

if __name__ == '__main__':

    for i in range(5):
        p = Process(target=task)
        p.start()

还剩1
还剩1
还剩1
还剩1
还剩1
进程6292 抢票成功
进程10604 抢票成功
进程19280 抢票成功
进程272 抢票成功
进程12272 抢票成功

这时就需要对线程或者进程加锁,以保证一个线程或进程在对共享对象进行修改时,其他的线程或进程无法访问这个对象,直至获取锁的线程的操作执行完毕后释放锁。所以,锁在多线程和多进程中起到一个同步的作用,以保护每个线程和进程必要操作的完整执行。

#线程锁
from threading import Thread,Lock

x = 0
mutex = Lock()
def task():
    global x
    mutex.acquire()
    for i in range(200000):
        x = x+1

    mutex.release()

if __name__ == '__main__':
    t1 = Thread(target=task)
    t2 = Thread(target=task)
    t3 = Thread(target=task)
    t1.start()
    t2.start()
    t3.start()
    t1.join()
    t2.join()
    t3.join()
    print(x)

600000

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

def search():
    time.sleep(1) # 模拟网络io
    with open('db.txt',mode='rt',encoding='utf-8') as f:
        res = json.load(f)
        print(f'还剩{res["count"]}')

def get():
    with open('db.txt',mode='rt',encoding='utf-8') as f:
        res = json.load(f)
        # print(f'还剩{res["count"]}')
    time.sleep(1) # 模拟网络io
    if res['count'] > 0:
        res['count'] -= 1
        with open('db.txt',mode='wt',encoding='utf-8') as f:
            json.dump(res,f)
            print(f'进程{os.getpid()} 抢票成功')
        time.sleep(1.5) # 模拟网络io
    else:
        print('票已经售空啦!!!!!!!!!!!')

def task(lock):
    search()

    # 锁住
    lock.acquire()
    get()
    lock.release()
    # 释放锁头

if __name__ == '__main__':
    lock = Lock() # 写在主进程是为了让子进程拿到同一把锁.
    for i in range(15):
        p = Process(target=task,args=(lock,))
        p.start()
        # p.join()

    #  进程锁 是把锁住的代码变成了串行
    #  join 是把所有的子进程变成了串行


# 为了保证数据的安全,串行牺牲掉效率.

还剩1
还剩1
还剩1
还剩1
还剩1
进程16868 抢票成功
票已经售空啦!!!!!!!!!!!
票已经售空啦!!!!!!!!!!!
票已经售空啦!!!!!!!!!!!
票已经售空啦!!!!!!!!!!!

原文地址:https://www.cnblogs.com/MrYang161/p/11543145.html