MST
星途 面试题库

面试题:Python多线程与异步编程的资源竞争处理

在Python多线程编程中,我们常用锁机制来处理资源竞争问题。而异步编程虽不存在线程资源竞争,但在异步I/O操作时可能会遇到共享资源的访问冲突。请详细说明如何在多线程和异步编程中有效处理资源竞争,并且分析这两种处理方式在原理和实现上的异同点。
50.3万 热度难度
编程语言Python

知识考点

AI 面试

面试题答案

一键面试

多线程中处理资源竞争

在多线程编程中,通过锁机制(如threading.Lock)来处理资源竞争。

  1. 原理:锁本质上是一个标志,当一个线程获取到锁时,其他线程就无法获取,直到该线程释放锁。这样可以保证在同一时间只有一个线程能够访问共享资源,避免资源竞争。
  2. 实现示例
import threading

# 共享资源
counter = 0
lock = threading.Lock()

def increment():
    global counter
    for _ in range(1000000):
        lock.acquire()
        try:
            counter += 1
        finally:
            lock.release()


thread1 = threading.Thread(target=increment)
thread2 = threading.Thread(target=increment)

thread1.start()
thread2.start()

thread1.join()
thread2.join()

print(counter)

在上述代码中,lock.acquire()获取锁,lock.release()释放锁,try - finally语句确保无论在counter += 1过程中是否发生异常,锁都会被释放。

异步编程中处理资源竞争

在异步编程(如使用asyncio库)中,通过asyncio.Lock来处理共享资源的访问冲突。

  1. 原理:与多线程锁类似,asyncio.Lock也是一个标志,当一个协程获取到锁时,其他协程必须等待锁的释放才能获取锁并访问共享资源。但异步编程是基于事件循环的单线程执行模型,协程的切换是在代码执行到await语句时主动让出控制权,而不是像多线程那样由操作系统调度。
  2. 实现示例
import asyncio

# 共享资源
counter = 0
lock = asyncio.Lock()


async def increment():
    global counter
    for _ in range(1000000):
        await lock.acquire()
        try:
            counter += 1
        finally:
            lock.release()


async def main():
    task1 = asyncio.create_task(increment())
    task2 = asyncio.create_task(increment())

    await task1
    await task2


if __name__ == "__main__":
    asyncio.run(main())
    print(counter)

在上述代码中,await lock.acquire()获取锁,lock.release()释放锁,try - finally语句确保无论在counter += 1过程中是否发生异常,锁都会被释放。

异同点分析

  1. 相同点
    • 目的相同:两者都是为了处理共享资源的竞争问题,确保同一时间只有一个执行单元(线程或协程)能够访问共享资源,防止数据不一致等问题。
    • 实现方式类似:都通过锁机制来实现,获取锁才能访问共享资源,访问完毕后释放锁。都使用try - finally结构来确保锁在使用完毕后被正确释放,即使在访问共享资源过程中发生异常。
  2. 不同点
    • 原理不同:多线程基于操作系统的线程调度,多个线程可以并行执行(多核CPU),资源竞争是由于多个线程同时访问共享资源。而异步编程基于单线程的事件循环,协程通过await语句主动让出执行权,资源竞争是由于异步I/O操作等导致协程切换时对共享资源的访问冲突。
    • 性能和适用场景不同:多线程适用于CPU密集型任务和需要利用多核CPU的场景,但线程创建和切换开销较大。而异步编程适用于I/O密集型任务,通过减少线程切换开销提高性能,在单线程内高效处理大量I/O操作。