Python系统学习第二十五课

本文探讨了多线程编程中的共享变量问题,介绍了锁、信号灯等同步机制,包括死锁现象及其避免方法。通过Python示例展示了锁的使用,生产者消费者模型,以及如何预防死锁。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

共享变量

  • 当多个线程同时访问同一个变量的时候,会产生共享变量的问题
  • 解决变量
    • 锁,信号灯
    • 锁(Lock):
      • 是一个标志,表示一个线程在占用一些资源
      • 使用方法
        • 上锁
        • 使用共享资源,放心使用
        • 取消锁,释放锁
      • 锁谁:哪个资源需要多个线程共享,锁哪个
      • 理解锁:锁其实不是锁住谁,而是一个令牌
    • 线程安全问题:
      • 如果一个变量/资源,他对于多线程来讲,不用加锁也不会引起任何问题,则成为线程安全
      • 线程不安全变量类型:list, set, dict
      • 线程安全变量类型:queue
    • 生产者消费者问题
      • 一个模型,可以用来搭建消息队列
      • queue是一个用来存放变量的数据结构,特点是先进先出,内部元素排队,可以理解成一个特殊的list
#每次执行都产生不同的值
import threading

sum = 0
loopSum = 1000000

def myAdd():
    global  sum, loopSum
    for i in range(1, loopSum):
        sum += 1

def myMinu():
    global  sum, loopSum
    for i in range(1, loopSum):
        sum -= 1

if __name__ == '__main__':
    print("Starting ....{0}".format(sum))

    # 开始多线程的实例,看执行结果是否一样
    t1 = threading.Thread(target=myAdd, args=())
    t2 = threading.Thread(target=myMinu, args=())

    t1.start()
    t2.start()

    t1.join()
    t2.join()

    print("Done .... {0}".format(sum))
Starting ....0
Done .... -11539
import threading

sum = 0
loopSum = 1000000


lock = threading.Lock()


def myAdd():
    global  sum, loopSum

    for i in range(1, loopSum):
        # 上锁,申请锁
        lock.acquire()
        sum += 1
        # 释放锁
        lock.release()


def myMinu():
    global  sum, loopSum
    for i in range(1, loopSum):
        lock.acquire()
        sum -= 1
        lock.release()

if __name__ == '__main__':
    print("Starting ....{0}".format(sum))

    # 开始多线程的实例,看执行结果是否一样
    t1 = threading.Thread(target=myAdd, args=())
    t2 = threading.Thread(target=myMinu, args=())

    t1.start()
    t2.start()

    t1.join()
    t2.join()

    print("Done .... {0}".format(sum))

Starting ....0
Done .... 0
#生产者消费者模型
import threading
import time

# Python2
# from Queue import Queue

# Python3
import queue


class Producer(threading.Thread):
    def run(self):
        global queue
        count = 0
        while True:
            # qsize返回queue内容长度
            if queue.qsize() < 1000:
                for i in range(100):
                    count = count +1
                    msg = '生成产品'+str(count)
                    # put是网queue中放入一个值
                    queue.put(msg)
                    print(msg)
            time.sleep(0.5)


class Consumer(threading.Thread):
    def run(self):
        global queue
        while True:
            if queue.qsize() > 100:
                for i in range(3):
                    # get是从queue中取出一个值
                    msg = self.name + '消费了 '+queue.get()
                    print(msg)
            time.sleep(1)


if __name__ == '__main__':
    queue = queue.Queue()

    for i in range(500):
        queue.put('初始产品'+str(i))
    for i in range(2):
        p = Producer()   #两个生产者
        p.start()
    for i in range(5):   #五个消费者
        c = Consumer()
        c.start()
  • 死锁问题
#死锁案例
import threading
import time

lock_1 = threading.Lock()
lock_2 = threading.Lock()

def func_1():
   print("func_1 starting.........")
   lock_1.acquire()
   print("func_1 申请了 lock_1....")
   time.sleep(2)
   print("func_1 等待 lock_2.......")
   lock_2.acquire()
   print("func_1 申请了 lock_2.......")

   lock_2.release()
   print("func_1 释放了 lock_2")

   lock_1.release()
   print("func_1 释放了 lock_1")

   print("func_1 done..........")

def func_2():
   print("func_2 starting.........")
   lock_2.acquire()
   print("func_2 申请了 lock_2....")
   time.sleep(4)
   print("func_2 等待 lock_1.......")
   lock_1.acquire()
   print("func_2 申请了 lock_1.......")

   lock_1.release()
   print("func_2 释放了 lock_1")

   lock_2.release()
   print("func_2 释放了 lock_2")

   print("func_2 done..........")

if __name__ == "__main__":

   print("主程序启动..............")
   t1 = threading.Thread(target=func_1, args=())
   t2 = threading.Thread(target=func_2, args=())

   t1.start()
   t2.start()
# 锁1先醒了之后,等待锁2 的醒来,但是,锁2 一直在函数2中沉睡,所以就是说,没有释放锁2。形成死锁,所以使用的时候要注意
   t1.join()
   t2.join()

   print("主程序启动..............")
主程序启动..............
func_1 starting.........
func_2 starting.........
func_2 申请了 lock_2....
func_1 申请了 lock_1....
func_1 等待 lock_2.......
func_2 等待 lock_1.......
# 锁的等待时间问题

import threading
import time

lock_1 = threading.Lock()
lock_2 = threading.Lock()

def func_1():
    print("func_1 starting.........")
    lock_1.acquire(timeout=4)  #超时时间,等待时间是四秒,不能超过四秒
    print("func_1 申请了 lock_1....")
    time.sleep(2)
    print("func_1 等待 lock_2.......")

    rst = lock_2.acquire(timeout=2)
    if rst:
        print("func_1 已经得到锁 lock_2")
        lock_2.release()
        print("func_1 释放了锁 lock_2")
    else:
        print("func_1 注定没申请到lock_2.....")

    lock_1.release()
    print("func_1 释放了 lock_1")

    print("func_1 done..........")


def func_2():
    print("func_2 starting.........")
    lock_2.acquire()
    print("func_2 申请了 lock_2....")
    time.sleep(4)
    print("func_2 等待 lock_1.......")
    lock_1.acquire()
    print("func_2 申请了 lock_1.......")

    lock_1.release()
    print("func_2 释放了 lock_1")

    lock_2.release()
    print("func_2 释放了 lock_2")

    print("func_2 done..........")

if __name__ == "__main__":

    print("主程序启动..............")
    t1 = threading.Thread(target=func_1, args=())
    t2 = threading.Thread(target=func_2, args=())

    t1.start()
    t2.start()

    t1.join()
    t2.join()

    print("主程序结束..............")

  • semphore
    • 允许一个资源由多个线程使用
import threading
import time

# 参数定义最多几个线程同时使用资源
semaphore = threading.Semaphore(3)

def func():
    if semaphore.acquire():
        for i in range(5):
            print(threading.currentThread().getName() + ' get semaphore')
        time.sleep(15)
        semaphore.release()
        print(threading.currentThread().getName() + ' release semaphore')


for i in range(8):
    t1 = threading.Thread(target=func)
    t1.start()
  • threading.Timer
    • timer是利用多线程,在指定时间后启动一个功能
#案例
import threading
import time

def func():
    print("I am running.........")
    time.sleep(4)
    print("I am done......")



if __name__ == "__main__":
    t = threading.Timer(6, func)
    t.start()

    i = 0
    while True:
        print("{0}***************".format(i))
        time.sleep(3)
        i += 1

  • 可重入锁
    • 一个锁,可以被一个线程多次申请
    • 主要解决递归调用的时候,需要申请锁的情况
import threading
import time

class MyThread(threading.Thread):
    def run(self):
        global num
        time.sleep(1)

        if mutex.acquire(1):
            num = num+1
            msg = self.name+' set num to '+str(num)
            print(msg)
            mutex.acquire()
            mutex.release()
            mutex.release()

num = 0

mutex = threading.RLock()


def testTh():
    for i in range(5):
        t = MyThread()
        t.start()



if __name__ == '__main__':
    testTh()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值