Python 多线程中的 Join Lock 和 Event

Join 函数的作用

Join 函数的作用主要是提供当前线程阻塞,等待线程结束后,在执行下一个线程,保护线程通畅有序执行

如下当没有使用 join 时,主线程结束了子线程还在运行


def doWaiting1():
    print('start waiting1: ' + time.strftime('%H:%M:%S') + "\n")
    time.sleep(3)
    print("线程1奉命报道")
    print('stop waiting1: ' + time.strftime('%H:%M:%S') + "\n")
def doWaiting2():
    print('start waiting2: ' + time.strftime('%H:%M:%S') + "\n")
    time.sleep(8)
    print("线程2奉命报道")
    print('stop waiting2: ', time.strftime('%H:%M:%S') + "\n")

# 创建并开启线程1
thread1 = threading.Thread(target = doWaiting1)
thread1.start()
# thread1.join()

# 创建并开启线程2
thread2 = threading.Thread(target = doWaiting2)
thread2.start()
# thread2.join()

# 计时程序
print('start join: ' + time.strftime('%H:%M:%S')  )
print('end join: ' + time.strftime('%H:%M:%S') )
start waiting1: 20:44:06

start waiting2: 20:44:06
start join: 20:44:06

end join: 20:44:06
线程1奉命报道
stop waiting1: 20:44:09

线程2奉命报道
stop waiting2:  20:44:14

Lock 的作用

在同一进程下的线程间资源是共享的,使用线程锁可以有效的保护共享资源。资源共享意味着所有线程均可以修改资源,而线程的执行是抢占式的,cpu执行任务的时候是不定规律执行的,同时会执行多个语句,多个线程在同一个进程中可以并发执行,当第一个线程读取数据时,第二个线程在修改数据,将会导致冲突。如果发生数据修改的操作,为防止数据资源冲突,可以给线程加锁,以保护资源。

线程锁原理:只有当被加锁的线程执行完毕,并释放锁,其他线程才可以对该线程所占用的资源进行操作使用

如下当不设进程锁时,会出现打印错乱,就是因为进程之间抢占资源造成的


lock = threading.Lock()

def add1():
    global a
    # lock.acquire()
    for i in range(10000):
        a = a+1
        print(a)
    # lock.release()

def add2():
    global a
    # lock.acquire()
    for i in range(10000):
        a = a+1
        print(a)
    # lock.release()

a = 1
t1 = threading.Thread(target=add1, )
t2 = threading.Thread(target=add1, )
t1.start()
t2.start()

Event 的使用

set() — 全局内置标志Flag,将标志Flag 设置为 True,通知在等待状态(wait)的线程恢复运行;

isSet() — 获取标志Flag当前状态,返回True 或者 False;

wait() — 一旦调用,线程将会处于阻塞状态,直到等待其他线程调用set()函数恢复运行;

clear() — 将标志设置为False;

Event 可以用来控制一个线程中不同子功能的开启,也可以用来实现两个线程之间的联动,即一个线程满足某种条件触发另外一个线程功能的启动


import threading
from time import sleep

event = threading.Event()

def test(n):
    while not event.is_set():
        print('event is not set')
        sleep(1)
    event.wait()
    while event.is_set():
        print('event is set')
        sleep(1)

if __name__ == '__main__':
    t = threading.Thread(target=test, args=(1, ))
    t.start()
    sleep(3)
    print('----- event is set -----')
    event.set()
    sleep(3)
    print('----- event is clear -----')
    event.clear()
event is not set
event is not set
event is not set
----- event is set -----
event is set
event is set
event is set
----- event is clear -----

生产者与消费之--Event版

# -*- coding:utf-8 -*-
import threading
import time
import queue


event = threading.Event()
goods = queue.Queue(5)
num = 0


class Producer(threading.Thread):
    def run(self):
        global num
        while True:
            if goods.empty():
                event.clear()
                for _ in range(5):
                    goods.put('商品-' + str(num))
                    print('生产了商品-{0}.'.format(str(num)))
                    num += 1
                    time.sleep(1)
                event.set()


class Customer(threading.Thread):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.money = 7

    def run(self):
        while self.money:
            event.wait()
            self.money -= 1
            print('{0} 买了一个{1}.'.format(
                threading.current_thread().name, goods.get()))
            time.sleep(1)
        print('{0}没钱了,回家.'.format(threading.current_thread().name))


if __name__ == '__main__':
    p = Producer(daemon=True)
    c1 = Customer(name='Alice')
    c2 = Customer(name='Bob')
    c2.start()
    p.start()
    c1.start()
    c1.join()
    c2.join()
posted @ 2023-02-21 22:22  可乐芬达  阅读(83)  评论(0编辑  收藏  举报