9、第七 - 网络编程基础 -线程锁(互拆锁Mutex)--threading.Lock()

  

  互斥锁的概念理解:Python编程中,引入了对象互斥锁的概念,来保证共享数据操作的完整性。每个对象都对应于一个可称为” 互斥锁” 的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。在Python中我们使用threading模块提供的Lock类。锁的意义,就是只允许一个线程对数据进行更改。

  Python threading模块有两类锁:互斥锁(threading.Lock )和递归锁(threading.RLock)。两者的用法基本相同,具体如下:

lock = threading.Lock()
lock.acquire()
dosomething……
lock.release()

举例如下:

      一个进程下可以启动多个线程,多个线程共享父进程的内存空间,也就意味着每个线程可以访问同一份数据,此时,如果2个线程同时要修改同一份数据。就会出现数据不一致的情况。

A、加等待时间time.sleep

import threading #导入threading模块
import time #导入time模块

class MyThread(threading.Thread):  # 通过继承创建类
    def __init__(self,threadname):  # 初始化方法
        super(MyThread,self).__init__()  # 调用父类的初始化方法

    def run(self): # 定义run方法
        global x  # 使用global表明x为全局变量
        for i in range(3):
            x += 1
        time.sleep(2) # 调用sleep函数,让线程休眠3秒
        print(x)

t1 = []     #定义空列表
x = 0       #将x赋值为0

for i in range(5):
    t = MyThread("i")  # 类实例化
    t1.append(t)  # 将类对象添加到列表中

for i in t1:
    i.start()
输出:
/Library/Frameworks/Python.framework/Versions/3.5/bin/python3.5 /Users/mac/PycharmProjects/untitled2/51CTO/6day/线程锁.py
15
15
15
15
15

 注:为什么结果都是一样呢?关键在于global 行和 time.sleep行:

  • 由于x是一个全局变量,所以每次循环后 x 的值都是执行后的结果值;
  • 由于该代码是多线程的操作,所以在sleep 等待的时候,之前已经执行完成的线程会在这等待,而后续的进程在等待2s这段时间也执行完成,等待print。同样由于global 的原理,x被重新斌值。所以打印出的结果全是15 ;
  • 便于理解,可以尝试将sleep等注释,你再看下结果,就会发现有不同。

B、注释time.sleep

import threading #导入threading模块
import time #导入time模块

class MyThread(threading.Thread):  # 通过继承创建类
    def __init__(self,threadname):  # 初始化方法
        super(MyThread,self).__init__()  # 调用父类的初始化方法

    def run(self): # 定义run方法
        global x  # 使用global表明x为全局变量
        for i in range(3):
            x += 1
        #time.sleep(2) # 调用sleep函数,让线程休眠3秒
        print(x)

t1 = []     #定义空列表
x = 0       #将x赋值为0

for i in range(5):
    t = MyThread("i")  # 类实例化
    t1.append(t)  # 将类对象添加到列表中

for i in t1:
    i.start()
输出:
/Library/Frameworks/Python.framework/Versions/3.5/bin/python3.5 /Users/mac/PycharmProjects/untitled2/51CTO/6day/线程锁.py
3
6
9
12
15

注:前后调用,按顺序打印。

C、所以在实际应用中,也会出现类似于sleep等待的情况。在前后调用有顺序或打印有输出的时候,就会现并发竞争,造成结果或输出紊乱。这里就引入了锁的概念,上面的代码修改下: 

import threading #导入threading模块
import time #导入time模块

class MyThread(threading.Thread):  # 通过继承创建类
    def __init__(self,threadname):  # 初始化方法
        super(MyThread,self).__init__()  # 调用父类的初始化方法

    def run(self): # 定义run方法
        global x  # 使用global表明x为全局变量
        lock.acquire()
        for i in range(3):
            x += 1
        time.sleep(2) # 调用sleep函数,让线程休眠3秒
        print(x)
        lock.release()

lock = threading.Lock() # 调用lock的release方法  ---改为 threading.RLock()效果一样
t1 = []     #定义空列表
x = 0       #将x赋值为0

for i in range(5):
    t = MyThread("i")  # 类实例化
    t1.append(t)  # 将类对象添加到列表中

for i in t1:
    i.start()

输出:
3
6
9
12
15

 附加:另外使用join 貌似也可以实现上述所说的加锁的情况如下:

#注释t.join 
import time,threading

def addNum():
    global num
    print("get num:",num)
    time.sleep(2)
    num -= 1

num = 5
thread_list=[]
for i in range(5):
    t = threading.Thread(target=addNum)
    t.start()
    #t.join() #使进程等待,处理完成一个到一个
    thread_list.append(i)

print('final num',num)
输出:
get num: 5
get num: 5
get num: 5
get num: 5
get num: 5
final num 5
=======================================
#去掉注释
import time,threading

def addNum():
    global num
    print("get num:",num)
    time.sleep(2)
    num -= 1

num = 5
thread_list=[]
for i in range(5):
    t = threading.Thread(target=addNum)
    t.start()
    t.join()
    thread_list.append(i)

print('final num',num)
输出:
get num: 5
get num: 4
get num: 3
get num: 2
get num: 1
final num 0

for循环5次,根据num为 5依次递减

  备注:加锁的结果会造成阻塞,而且会造成机器资源开销大。会根据顺序由并发的多线程按顺序输出,如果后面的线程执行过快,需要等待前面的进程结束后其才能结束。类似这样的场景,可以使用队列工具去解决。

 

转载于:https://www.cnblogs.com/chen170615/p/8732883.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值