zoukankan      html  css  js  c++  java
  • python_并发编程——多线程2

    1.互斥锁

    import time
    from threading import Thread,Lock
    
    def func1(lock):
        global n
        lock.acquire()  #加锁
        temp = n
        time.sleep(0.2)
        n = temp -1
        lock.release()  #解锁
    
    n = 10
    t_list = []
    lock = Lock()
    for i in range(10):
        t1 = Thread(target=func1,args=(lock,))
        t1.start()
        t_list.append(t1)
    for i in t_list:
        i.join()
    print(n)

    结果:  牺牲了执行的速度,但保证了数据的安全性。

     2.递归锁

    from threading import Thread,RLock
    
    def func1(name):
        lock1.acquire()
        print('{}拿到第一把钥匙!'.format(name))
        lock2.acquire()
        print('{}拿到第二把钥匙!'.format(name))
        print('{}进入了房间'.format(name))
        lock2.release() #归还第二把钥匙
        lock1.release() #归还第一把钥匙
    
    lock1 = RLock()   #锁1
    lock2 = RLock()   #锁2
    
    for i in range(10):
        Thread(target=func1,args=(i,)).start()

    结果:  当同时需要拿到两把钥匙才可以执行代码时,容易出现分别两个不同的线程,每个线程各拿到一把钥匙时,就会出现死锁,所有递归锁就可以解决这样的问题。

    3.信号量

    from threading import Semaphore,Thread
    import time
    
    def func(sem,a,b):
        sem.acquire()
        time.sleep(1)   #增加1秒之的间隔,更容易看出执行结果
        print(a+b)
        sem.release()
    
    sem = Semaphore(4)  #定义一个信号量对象,设置好信号量的数量
    for i in range(10):
        t = Thread(target=func,args=(sem,i,i+5))    #将信号来传递进子线程要执行的函数
        t.start()

    结果:只能同时有4个进程访问函数。

    4.事件

      当事件被创建出来的时候,他的状态是False,事件的状态可以控制wait(),当事件的状态为True时,wait()非阻塞,当事件状态为False时,wait()阻塞。

      有两个方法可以修改事件的状态,clear():设置事件的状态为False,set():设置事件的状态为True。

      应用:多线程模拟检测数据库链接状态:

    import time
    import random
    from threading import Thread,Event
    
    def connect_db(e):
        count = 0   #计数器
        while count < 3:
            e.wait(1)    #根据事件e的状态选择是否阻塞,括号里面加参数,设置阻塞时间1秒
            if e.is_set() == True:  #is_set():检测事件e的状态
                print('数据库链接成功!')
                break
            else:
                count += 1
                print('第{}次链接数据库失败!'.format(count))
        else:
            print('连接数据库超时!')
    
    def check_web(e):
        time.sleep(random.randint(0,3))     #模拟网络延时0-3s
        e.set()     #将事件对象状态设置为True
    
    e = Event() #创建一个事件对象
    t1 = Thread(target=connect_db,args=(e,))
    t2 = Thread(target=check_web,args=(e,))
    t1.start()
    t2.start()

    结果:

    5.条件

      条件类似一个高级的锁,他除了acquire()方法和release()方法之后还有两个方法,wait()方法和notify()方法。

    一个条件被创建之初,默认会有一个状态,这个状态会影响wait()方法,一直处于等待状态。

    notify(int数据类型)方法的括号中有一个int类型的数值,这个方法的作用是制作钥匙,括号中填写制作钥匙的数量。

    wait和notify 都需要在acquire和release之间。

    from threading import Thread,Condition
    
    def func(con,i):
        con.acquire()
        con.wait()  #等待
        print('在第{}个函数中!'.format(i))
        con.release()
    
    con = Condition()   #创建一个条件对象
    for i in range(10):
        Thread(target=func,args=(con,i)).start()
    while True:
        num = int(input('输入一个整数:'))
        con.acquire()
        con.notify(num)     #造钥匙
        con.release()

    结果:  造多少个钥匙,就多少个线程访问函数。

    6.定时器

    from threading import Timer
    
    def func():
        print('定时开启线程!')
    
    #两个值 第一个:时间,以秒为单位,第二个:函数名
    Timer(3,func).start()   #3秒周之后开启一个线程执行函数func

    结果:3秒后,打印‘定时开启线程!

    7.队列

      队列是安全的,队列中的数据先进先出。

    import queue
    
    q = queue.Queue(10)   # 创建一个队列对象,设置队列大小
    for i in range(10):
        q.put(i)    # 向队列中存数据
    for i in range(10):
        print(q.get())  # 从队列中获取数据

    结果:

    当队列中没有值时,还继续用get方法获取队列中的值,会一直等待,当队列中值满了的时候,还继续用put方法想队列中存放数据,也会一直阻塞。

    put_nowait()方法:

    import queue
    
    q = queue.Queue(10)   # 创建一个队列对象,设置队列大小
    for i in range(11):
        q.put(i)    # 向队列中存数据
        q.put_nowait()  # 当队列中值满了的时候,再继续向队列中存值,会报错

    结果:

    get_nowait()方法:

    import queue
    
    q = queue.Queue(10)
    q.put('wdc')
    print(q.get())
    q.get_nowait()  # 当队列中没有值的时候,会报错

    结果:

    8.栈

      先进后出。

    import queue
    
    q = queue.LifoQueue(10)  # 创建一个栈对象,大小为10
    for i in range(10):
        q.put(i)
    for i in range(10):
        print(q.get())

    结果:

    9.优先级队列

    import queue
    
    q = queue.PriorityQueue()   # 创建一个优先级队列对象
    q.put((20,'a'))  # 向优先级队列放数据时,要放一个元组,第一个代表优先级,第二个是要存放的数据
    q.put((30,'b'))
    q.put((10,'c'))
    print(q.get())

    结果:  先获取优先级数值小的元组。

    import queue
    
    q = queue.PriorityQueue()   # 创建一个优先级队列对象
    
    q.put((10,'s'))
    q.put((20,'a'))  # 向优先级队列放数据时,要放一个元组,第一个代表优先级,第二个是要存放的数据
    q.put((30,'b'))
    q.put((10,'c'))
    q.put((10,'d'))
    print(q.get())

    结果: 当优先级相同时,会根据值的ascii编码的顺序获取。

  • 相关阅读:
    error C4996: Function call with parameters that may be unsafe
    C mysql (C API Commands out of sync; you can't run this command now)
    messagpack的使用
    关于openssl的编译与使用
    openssl & openssh
    解决SOCKET通信 ERROR_INSUFFICIENT_BUFFER错误
    C++ mysql 乱码
    [置顶] docker1.12--docker命令行帮助文档
    [置顶] kubernetes资源类型--secret和Service Account
    [置顶] kubernetes资源类型--Volume
  • 原文地址:https://www.cnblogs.com/wangdianchao/p/12115939.html
Copyright © 2011-2022 走看看