python多线程

多线程

简介

多线程是一种并发编程的技术,允许程序同时执行多个任务或操作。线程是操作系统调度的基本单位,而进程是资源分配的基本单位,一个进程可以包含多个线程。
并发执行是指两个或多个任务或操作在同一时间段内交替执行,并行执行是指两个或多个任务或操作在同一时刻同时执行。如果是多核CPU,则可以实现真正的并行执行。

多线程的优点:

  • 可以同时执行多个任务,提高程序的运行效率。
  • 可以及时响应用户的请求,通过使用单独的线程来处理用户请求,不会因为一个线程的阻塞而影响其他线程的运行。
  • 与多进程相比,线程的创建和切换开销小,可以节省系统资源。

多线程的缺点:

  • 线程之间共享数据时,需要进行同步,否则会导致数据错乱。
  • 线程的执行顺序无法预测,因而可能导致程序的行为不一致。
  • 线程的调试和维护都相对复杂。

threading模块

Python的threading模块提供了对多线程的支持。它提供了Thread类来代表线程对象,提供了Lock、RLock、Condition、Semaphore、Event等类来提供对线程同步的支持。

创建线程

使用Thread类可以创建线程对象,并指定线程的运行函数。

import threading

def worker():
    print('Worker')


t = threading.Thread(target=worker)
t.start()

Thread类的构造函数可以接收以下参数:

  • group:线程组,默认值为None。
  • target:线程运行函数。
  • name:线程名称,默认值为None。
  • args:传递给线程函数的参数,默认值为None。
  • kwargs:传递给线程函数的关键字参数,默认值为None。

start()方法启动线程。

线程同步

多线程编程中,线程同步是指多个线程之间需要共享某些资源,因此需要对共享资源进行保护,以避免数据竞争和线程安全问题。

Python的threading模块提供了Lock、RLock、Condition、Semaphore、Event等类来提供对线程同步的支持。

Lock

Lock类是互斥锁,用于在同一时刻只允许一个线程对共享资源进行访问。

import threading

counter = 0
lock = threading.Lock()

def increment():
    global counter
    # 获取锁
    lock.acquire()
    try:
        # 访问共享资源
        counter += 1
    finally:
        # 释放锁
        lock.release()

threads = []
for _ in range(10):
    thread = threading.Thread(target=increment)
    thread.start()
    threads.append(thread)

for thread in threads:
    thread.join() # 等待所有线程结束

print("Counter:", counter)  # 10

acquire()方法获取锁,如果锁已经被其他线程获取,则当前线程会被阻塞,直到锁被释放。release()方法释放锁。

RLock

RLock类是可重入锁,它可以对共享资源进行递归锁定,即同一线程可以对同一资源进行多次加锁。与普通的Lock相比,RLock允许同一个线程多次获取锁,而普通的Lock不允许同一个线程在没有释放锁的情况下再次获取锁(会导致死锁)。

import threading

rlock = threading.RLock()

def foo():
    # with语句会自动获取锁,并在退出with语句时自动释放锁
    with rlock:
        bar()  # 在同一线程内可以嵌套使用RLock

def bar():
    with rlock:
        print("Hello from bar")

# 创建线程
thread = threading.Thread(target=foo)
thread.start()
thread.join()

Condition

Condition是基于Lock的。Condition提供了一个更高级别的线程同步原语,允许线程等待某些条件的发生,然后再继续执行。

Condition结合了LockEventQueue的功能。它提供了wait()notify()notify_all()等方法来实现线程之间的协作。

生产者-消费者模型:

import threading
import time

buffer = [] # 共享资源
buffer_size = 5 # 缓冲区大小
condition = threading.Condition() # 条件变量

# 生产者
def producer():
    global buffer
    for i in range(10):
        with condition:
            while len(buffer) >= buffer_size:
                print("Buffer is full, producer is waiting")
                condition.wait()
            buffer.append(i)
            print(f"Produced {i}")
            condition.notify()

# 消费者
def consumer():
    global buffer
    while True:
        with condition:
            while len(buffer) == 0:
                print("Buffer is empty, consumer is waiting")
                condition.wait()
            item = buffer.pop(0)
            print(f"Consumed {item}")
            condition.notify()

# 创建生产者和消费者线程
producer_thread = threading.Thread(target=producer)
consumer_thread = threading.Thread(target=consumer)

# 启动线程
producer_thread.start()
consumer_thread.start()

# 等待线程结束
producer_thread.join()
consumer_thread.join()

print("All threads finished")

运行结果:

wait()方法使线程阻塞,直到其他线程调用notify()notifyAll()方法唤醒它。notify()方法唤醒一个线程,notifyAll()方法唤醒所有等待线程。
在这里插入图片描述

Semaphore

Semaphore类是信号量,用于控制对共享资源的访问数量。

同样可以使用Semaphore类来实现生产者-消费者模型:

import threading
import time

buffer = []  # 共享资源
buffer_size = 5  # 缓冲区大小
empty = threading.Semaphore(buffer_size)  # 空闲缓冲区空间的信号量
full = threading.Semaphore(0)  # 已填充缓冲区空间的信号量
mutex = threading.Lock()  # 互斥锁,用于保护对缓冲区的访问

# 生产者
def producer():
    global buffer
    for i in range(10):
        empty.acquire()  # 获取一个空闲缓冲区空间
        mutex.acquire()  # 获取对缓冲区的访问权
        buffer.append(i)
        print(f"Produced {i}")
        mutex.release()  # 释放对缓冲区的访问权
        full.release()  # 增加已填充缓冲区空间的信号量

# 消费者
def consumer():
    global buffer
    while True:
        full.acquire()  # 获取一个已填充的缓冲区空间
        mutex.acquire()  # 获取对缓冲区的访问权
        item = buffer.pop(0)
        print(f"Consumed {item}")
        mutex.release()  # 释放对缓冲区的访问权
        empty.release()  # 增加空闲缓冲区空间的信号量

# 创建生产者和消费者线程
producer_thread = threading.Thread(target=producer)
consumer_thread = threading.Thread(target=consumer)

# 启动线程
producer_thread.start()
consumer_thread.start()

# 等待线程结束
producer_thread.join()
consumer_thread.join()

print("All threads finished")

acquire()方法获取信号量,如果信号量已经被其他线程获取,则当前线程会被阻塞,直到信号量被释放。release()方法释放信号量。

Event

Event类是事件,用于线程间通信,Event允许一个或多个线程等待某个事件的发生。它通常用于线程间的通信和协调,典型的用法包括线程等待某个条件的触发,或者多个线程在某个事件上等待。

import threading
import time

# 事件对象
event = threading.Event()

# 线程函数,等待事件发生后打印消息
def wait_for_event():
    print("Thread waiting for event...")
    event.wait()  # 等待事件发生
    print("Thread event happened!")

# 线程函数,设置事件
def set_event():
    time.sleep(2)  # 等待2秒钟
    print("Setting event...")
    event.set()  # 设置事件

# 创建并启动线程
thread1 = threading.Thread(target=wait_for_event)
thread2 = threading.Thread(target=set_event)
thread1.start()
thread2.start()

# 等待线程结束
thread1.join()
thread2.join()

print("Main thread exiting.")

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

wait()方法使线程阻塞,直到其他线程调用set()方法设置事件。set()方法设置事件,使线程阻塞的wait()方法解除阻塞。

Queue

Queue可以用来在线程间传递数据。
模拟一个计算任务队列:

import threading
import queue
import time

# 定义一个队列用于存放计算任务
task_queue = queue.Queue()

# 生产者线程,负责生成计算任务
def producer():
    for i in range(10):
        task_queue.put((i, i+1))  # 添加任务,这里模拟计算 (i, i+1)
        print(f"Produced task {i}")  # 输出生产任务的信息
        time.sleep(0.5)

    # 所有任务添加完毕后,向队列中放入None作为结束信号
    task_queue.put(None)

# 消费者线程,负责处理计算任务
def consumer():
    while True:
        task = task_queue.get()
        if task is None:
            task_queue.task_done()
            break
        
        result = task[0] + task[1]  # 计算结果
        print(f"Task {task} => Result {result}")  # 输出计算结果的信息
        task_queue.task_done()

# 创建并启动生产者线程和消费者线程
producer_thread = threading.Thread(target=producer)
consumer_thread = threading.Thread(target=consumer)

producer_thread.start()
consumer_thread.start()

# 等待生产者线程完成
producer_thread.join()

# 等待所有任务完成
task_queue.join()

print("All tasks are completed.")

put()方法向队列中放入数据,get()方法从队列中获取数据。

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

线程的状态

Thread类使用is_alive()判断线程是否存活。

import threading

def worker():
    print('Worker')

t = threading.Thread(target=worker)
t.start()

print(t.ident)
  • 32
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值