python基础爬虫——多线程_线程等待和线程锁

本文介绍了Python中的线程等待和线程锁概念。线程等待通过`join()`函数实现,使得一个线程等待其他线程执行完成后再继续。线程锁则使用`threading.RLock`,通过`acquire()`和`release()`方法控制对公共资源的访问,保证并发安全。

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

困于心衡于虑而后作
今天的学习目标是:python的线程等待和线程锁

1.线程等待

线程等待
在多线程的程序中往往一个线程(例如主线程)要等待其他线程执行完毕才继续执行,
这可以用join函数,使用的方法是:
线程对象.join()
在一个线程代码中执行这条语句,当前的线程就会停止执行,
一直等到指定的线程对象的线程执行完毕后才继续执行
即这条语句启动阻塞等待的作用


# 主线程启动子线程等待结束后再执行
import threading
import time
import random


def reading():
    for i in range(5):
        print('reading', i)
        time.sleep(random.randint(1, 2))


t = threading.Thread(target=reading)
t.setDaemon(False)
t.start()
t.join()
print('the end')
# 由此可见主线程启动子线程t执行reading函数,t.join就会阻塞主线程,
# 一直等到t线程执行完毕后才结束t.join(),继续执行显示the end

运行结果:
在这里插入图片描述

# 子线程启动子线程等待结束后再执行
import threading
import time
import random


def reading():
    for i in range(5):
        print('reading ', i)
        time.sleep(random.randint(1, 2))


def test():
    r = threading.Thread(target=reading)
    r.setDaemon(True)
    r.start()
    r.join()
    print('test end')


t = threading.Thread(target=test)
t.setDaemon(False)
t.start()
t.join()
print('the end')

# 由此可见主线程启动t.join()会等待t线程结束,在test中再次启动r子线程,而且r.join()而阻塞t线程
# 等待r线程执行完毕后才结束r.join(),然后显示test end,之后t线程结束,再次结束t.join()
# 主线程显示the end后结束

运行结果:
在这里插入图片描述

2.线程锁

在多个线程的程序中有一个普遍存在的问题是,如果多个线程要竞争同时访问与改写公共资源
那么应该怎么样协调各个线程之间的关系,一个普遍使用的方法是使用线程锁,python使用threading.RLock类
来创建一个线程锁对象
lock=-threading.RLock()
这个对象lock有两个重要的方法是acquire()与release()
当执行:
lock.acquire()
语句强迫lock获取线程锁,
如果已经有了另外的线程先调用了acquire()方法获取了线程锁而还没有调用release()释放锁,
那么这个lock.acquire()就阻塞当前的线程,一直等待锁的控制权,
直到别的线程释放锁后lock.acquire()就获取锁并解除阻塞,线程继续执行

执行后线程要调用
lock.release()
释放锁,不然别的线程会一直得不到锁的控制权
使用acquire/release的工作机制我们可以把一段修改公共资源的代码用acquire()与release()夹起来,
这样就可以保证一次最多只有一个线程在修改公共资源

# 子线程a升序,子线程d降序
import threading
import time

lock = threading.RLock()
words = ['a', 'b', 'd', 'b', 'p', 'm', 'e', 'f', 'b']


def increase():
    global words
    for count in range(5):
        lock.acquire()
        print('a acquire')
        for i in range(len(words)):
            for j in range(i + 1, len(words)):
                if words[j] < words[i]:
                    t = words[i]
                    words[i] = words[j]
                    words[j] = t  # 这里需要注意,内容交换
        print('a ', words)
        time.sleep(1)
        lock.release()


def decrease():
    global words
    for count in range(5):
        lock.acquire()
        print('d acquire')
        for i in range(len(words)):
            for j in range(i + 1, len(words)):
                if words[j] > words[i]:
                    t = words[i]
                    words[i] = words[j]
                    words[j] = t
        print('d ', words)
        time.sleep(1)
        lock.release()


a = threading.Thread(target=increase)
a.setDaemon(False)
a.start()

d = threading.Thread(target=decrease)
d.setDaemon(False)
d.start()
print('the end')

# 由此可见,无论是increase还是decrease的排序过程,都是在获得锁的控制权下进行的,
# 因此排序过程中另一个线程必然处于等待状态,不会干扰本次排序,因此每次显示的结果不是升序就是降序的

运行结果:
在这里插入图片描述

# 子线程a升序,子线程d降序,使用线程锁不混乱
import threading
import time

lock = threading.RLock()
words = ['a', 'b', 'd', 'b', 'p', 'm', 'e', 'f', 'b']
s = ['a', 'b', 'c', 'd']


def asort():
    global s
    lock.acquire()
    for i in range(len(s)):
        for j in range(i + 1, len(s)):
            if s[i] > s[j]:
                t = s[i]
                s[i] = s[j]
                s[j] = t
            time.sleep(0.1)
    print(s)
    lock.release()


def dsort():
    global s
    lock.acquire()
    for i in range(len(s)):
        for j in range(i + 1, len(s)):
            if s[j] > s[i]:
                t = s[i]
                s[i] = s[j]
                s[j] = t
            time.sleep(0.1)
    print(s)
    lock.release()


def show():
    global s
    for e in s:
        print(e, end=' ')
    print()


show()
for i in range(5):
    a = threading.Thread(target=asort)
    a.setDaemon(False)
    d = threading.Thread(target=dsort)
    d.setDaemon(False)
    a.start()
    d.start()
# a.join()
# d.join()
show()
print('the end')
# 只有当上一次的线程的lock释放出来后,下一个线程才能获取线程锁,执行资源操作,
# 即要么执行从大到小的排序,要么执行从小到大的排序,资源操作不是同时执行的,资源的排序不会出现混乱的状态

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值