多线程无锁线程和有锁线程示例,适合初学者参考学习

准备在用多线程处理数据,但对全局公用数据(非self.的数据)如果用多线程来处理,就存在跑的快的线程如果对正在使用此数据的其他线程还在运算中就更改了这些全局变量数据值的情况,正在处理数据的线程因使用的原始数据被其他线程在运算过程中更改了,就将得到不到正确的计算结果,故就要在处理这些涉及全局变量数据时采用线程锁来锁定,处理完成后解除锁定,再允许其他线程处理这些全局变量。锁定数据过程中又相当于只有一个多线程了,对效率造成影响,所以全局变量的定义在多线程中应尽量少使用。下面作了一个示例,来比较用多线程处理全局变量的方法和能效比较。不锁线程时,我机器总用时(机器不同结果不同):2187毫秒,锁线程时4029毫秒,相当于锁线程是不锁线程的两倍,双线程实际每个线程有一半的时间被锁定并没有运行。不锁线程时,运算结果有非预期值出现,锁线程后没有非预期值出现。

"""
1示例:同时开启的多线程因线程处理时序不同,对共有全局变量的引用值可能是同预期值是不同的
2示例:使用线程锁,来避免1示例可能出现的情况,但会降低线程使用效率
"""
import threading
import time
from timeit import default_timer as timer
import time
from time import *

import sys
starttime=0.00 #线程起止时间
endtime=0.00
Lock = threading.Lock()  
# myThread继承父类(无锁示例),并进行重写
class myThread1(threading.Thread):
    # 重写父类的构造函数
    count=0
    lst=['类全局成员列表值=',0,'列表中的循环计数=',0]
    def __init__(self, number, index):
        threading.Thread.__init__(self)
        self.number = number  # 添加number变量
        self.id = index  # 添加id变量
        
    # 重写父类中的run函数
    def run(self):
        if(self.id==1):
            print(f"【线程开始】{self.name}")
            self.task1(self.number, self.id)
        elif(self.id==2):
            print(f"【线程开始】{self.name}")
            self.task2(self.number, self.id)
       # print("【线程结束】", self.name)
 
    # 重写父类析构函数
    def __del__(self):
        print("【线程销毁释放内存】", self.name)
 
 
    # 自定义的函数:供线程1调用
    def task1(self, number, id):
        count=1
        i=1
        while i <= number:    
           #sleep(0.1)
            myThread1.lst[1]=i    
            myThread1.lst[3]=count  
            myThread1.count+=1
            num=myThread1.count
            s=''
            sleep(0.04)          #因休眠期,可能存在其他跑得快的线程将此全局变量改了,即myThread.count不一定是连续的
            if(myThread1.count!=num):
                s='两值已不相同'
            print(f'\ntask1:线程{id}中lst={myThread1.lst},线程类全局计数count={myThread1.count},对比sleep前值={num}:{s}')
            i+=1  
            i+=1
            count+=1

    # 自定义的函数,供线程2调用
    def task2(self, number, id):
        count=1
        i=1
        m = 1
        while i <= number:    
            myThread1.lst[1]=i    
            myThread1.lst[3]=count  
            myThread1.count+=1
            num=myThread1.count
            s=''
            sleep(0.01)          #因休眠期,可能存在其他跑得快的线程将此全局变量改了,即myThread.count不一定是连续的
            if(myThread1.count!=num):
                s='两值已不相同'
            print(f'\ntask2:线程{id}中lst={myThread1.lst},线程类全局计数count={myThread1.count},对比sleep前值={num}:{s}')
            i+=1
            count+=1

 
# myThread2继承父类(有锁示例),并进行重写
class myThread2(threading.Thread):
    # 重写父类的构造函数
    count=0
    lst=['类全局成员列表值=',0,'列表中的循环计数=',0]
    def __init__(self, number, index):
        threading.Thread.__init__(self)
        self.number = number  # 添加number变量
        self.id = index  # 添加id变量
          
    # 重写父类中的run函数
    def run(self):
        if(self.id==1):
            print(f"【线程开始】{self.name}")
            self.task3(self.number, self.id)
        elif(self.id==2):
            print(f"【线程开始】{self.name}")
            self.task4(self.number, self.id)
       # print("【线程结束】", self.name)
 
    # 重写父类析构函数
    def __del__(self):
        print("【线程销毁释放内存】", self.name)
 
     # 自定义的函数:供线程2调用
    def task3(self, number, id):
        count=1
        i=1
        while i <= number:    
           #sleep(0.1)
            Lock.acquire()  # 设置线程锁
            myThread2.lst[1]=i    
            myThread2.lst[3]=count  
            myThread2.count+=1
            num=myThread2.count
            s=''
            sleep(0.04)          #因休眠期,可能存在其他跑得快的线程将此全局变量改了,即myThread.count不一定是连续的
            if(myThread2.count!=num):
                s='两值已不相同'
            print(f'\ntask3:线程{id}中lst={myThread2.lst},线程类全局计数count={myThread2.count},对比sleep前值={num}:{s}')
            Lock.release()  # 释放线程锁
            i+=1  
            i+=1
            count+=1

    # 自定义的函数,供线程2调用
    def task4(self, number, id):
        count=1
        i=1
        m = 1
        while i <= number:    
            Lock.acquire()  # 设置线程锁
            myThread2.lst[1]=i    
            myThread2.lst[3]=count  
            myThread2.count+=1
            num=myThread2.count
            s=''
            sleep(0.01)          #因休眠期,可能存在其他跑得快的线程将此全局变量改了,即myThread.count不一定是连续的
            if(myThread2.count!=num):
                s='两值已不相同'
            print(f'\ntask4:线程{id}中lst={myThread2.lst},线程类全局计数count={myThread2.count},对比sleep前值={num}:{s}')
            Lock.release()  # 释放线程锁
            i+=1
            count+=1


if __name__ == '__main__':
    print('开始示例1:开启两个线程,不锁线程......')
    starttime = timer()
    thread1 = myThread1(80, 1)  # 创建线程thread1:
    thread2 = myThread1(150, 2)  # 创建线程thread2:
    thread1.start()  # 启动线程1
    thread2.start()  # 启动线程2
    thread1.join()  # 等待线程1
    thread2.join()  # 等待线程2
    endtime = timer()
    sumtime=(endtime-starttime)*1000
    print(f'示例1运行总时间{sumtime}毫秒\n\n5秒后准备开始运行示例2:有锁线程.....')
    sleep(5)
    
    print('开始示例2:开启两个线程,锁线程......')
    starttime = timer()
    thread3 = myThread2(80, 1)   # 创建线程thread3:
    thread4 = myThread2(150, 2)  # 创建线程thread4:
    thread3.start()  # 启动线程3
    thread4.start()  # 启动线程4
    
    thread3.join()  # 等待线程3
    thread4.join()  # 等待线程4
    endtime = timer()
    sumtime=(endtime-starttime)*1000
    print(f'示例2运行总时间{sumtime}毫秒')

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mr_LuoWei2009

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值