Python的多线程

目录

两种方法实现多线程

Semaphore

Condition

Event(wait、set、clear)

Queue

Pool

Pipe


需要导入threading库中Thread类,例如 from threading import Thread

两种方法实现多线程

1、类继承Thread父类,并重写init方法(初始化需要接收的一些属性),run方法(里面编写多线程的业务逻辑),例如:

class MyThread(Thread):

    def __init__(self, num):
        self.num = num
        super().__init__()

    def run(self):
        count = self.num
        while count:
            print(f"{time.strftime('%H:%M:%S')} {threading.current_thread().name} 计数{count} ")
            time.sleep(2)
            count -= 1

2、不继承父类Thread,直接通过Thread类提供的初始化实例方法接收参数

def threading_task(num):
    count = num
    while count:
        print(f"{time.strftime('%H:%M:%S')} {threading.current_thread().name} 计数{count} ")
        time.sleep(2)
        count -= 1


my_thread1 = threading.Thread(target=threading_task, args=(3,), name='my_thread1')
my_thread2 = threading.Thread(target=threading_task, args=(2,), name='my_thread2')

3、选择上面任意一种方式生成thread的实例,调用start方法启动多线程 thread.start()

比如用上面1的实现方法调试:

if __name__ == "__main__":
    print(f"{time.strftime('%H:%M:%S')} 主进程开始")
    my_thread1 = MyThread(3)
    my_thread2 = MyThread(2)
    my_thread1.name = 'my_thread1'
    my_thread2.name = 'my_thread2'

    my_thread1.start()
    my_thread2.start()

    my_thread1.join()
    my_thread2.join()
    print(f"{time.strftime('%H:%M:%S')} 主进程结束")


22:21:32 主进程开始
22:21:32 my_thread1 计数3 
22:21:32 my_thread2 计数2 
22:21:34 my_thread2 计数1 22:21:34 my_thread1 计数2 

22:21:36 my_thread1 计数1 
22:21:38 主进程结束

注意:join的用法跟多进程一样,可以参考:Python的多进程_fighter_狂奔的博客-CSDN博客

比如用上面2的实现方法调试:

if __name__=='__main__':
    print(f"{time.strftime('%H:%M:%S')} 主进程开始")
    my_thread1 = threading.Thread(target=threading_task, args=(3,), name='my_thread1')
    my_thread2 = threading.Thread(target=threading_task, args=(2,), name='my_thread2')
    my_thread1.start()
    my_thread2.start()

    my_thread1.join()
    my_thread2.join()

    print(f"{time.strftime('%H:%M:%S')} 主进程结束")

运行结果:

22:18:06 主进程开始
22:18:06 my_thread1 计数3 
22:18:06 my_thread2 计数2 
22:18:08 my_thread2 计数1 22:18:08 my_thread1 计数2 

22:18:10 my_thread1 计数1 
22:18:12 主进程结束

注意:daemon的用法跟多进程一样,可以参考:Python的多进程_fighter_狂奔的博客-CSDN博客

Lock

线程锁(Thread Lock)是一种多线程编程中的同步机制,用于确保多个线程不会同时访问共享资源,从而避免竞争条件和数据损坏。下面是一个使用线程锁的Python多线程示例:

import threading

# 共享资源
counter = 0

# 创建一个线程锁
lock = threading.Lock()

# 线程函数,用于增加共享资源的值
def increment():
    global counter
    # 获取线程锁
    lock.acquire()
    for i in range(100000):
        counter += 1
    # 释放线程锁
    lock.release()

# 创建两个线程
thread1 = threading.Thread(target=increment)
thread2 = threading.Thread(target=increment)
thread3 = threading.Thread(target=increment)

# 启动线程
thread1.start()
thread2.start()
thread3.start()

# 等待线程完成
thread1.join()
thread2.join()
thread3.join()

# 打印最终的共享资源值
print("Final Counter:", counter)


Final Counter: 300000

Semaphore

Semaphore 是 Python 多线程编程中的同步原语之一,它是一个计数信号量,用于控制同时访问共享资源的线程数量。Semaphore 维护一个内部计数器,线程可以尝试获取信号量,如果计数器大于零,线程就能获取信号量,计数器减一;如果计数器为零,线程就需要等待,直到有其他线程释放信号量。

import threading

# 创建一个信号量,最大允许两个线程同时访问共享资源
import time

semaphore = threading.BoundedSemaphore(2)

# 共享资源
shared_resource = []

# 线程函数,用于访问共享资源
def access_shared_resource(thread_id):
    with semaphore:  # 尝试获取信号量
        shared_resource.append(thread_id)
        print(f"{time.strftime('%H:%M:%S')}")
        print(f"Thread {thread_id} accessed the shared resource")
        print(f"Shared Resource: {shared_resource}")
        time.sleep(2)


# 创建多个线程
threads = []
for i in range(5):
    thread = threading.Thread(target=access_shared_resource, args=(i,))
    threads.append(thread)

# 启动线程
for thread in threads:
    thread.start()

# 等待线程完成
for thread in threads:
    thread.join()

print("All threads have finished")

 调试结果:

22:57:50
Thread 0 accessed the shared resource
Shared Resource: [0]
22:57:50
Thread 1 accessed the shared resource
Shared Resource: [0, 1]
22:57:5222:57:52
Thread 3 accessed the shared resource
Thread 2 accessed the shared resource

Shared Resource: [0, 1, 3, 2]
Shared Resource: [0, 1, 3, 2]
22:57:54
Thread 4 accessed the shared resource
Shared Resource: [0, 1, 3, 2, 4]
All threads have finished

Process finished with exit code 0

Condition

Condition 是 Python 用于协调多个线程之间的操作顺序。Condition 允许线程等待某个条件成立,然后通知其他线程,以便它们可以执行相应的操作。

condition = threading.Condition()  两个线程同时使用这个对象用于控制两个线程的消息交互

condition.acquire() 获取锁,准备运行

condition.wait() 释放锁,阻塞中等待唤醒

condition.notify() 唤醒阻塞中的线程去运行

condition.release()  线程执行完成释放资源

import threading

# 共享资源
import time

shared_resource = []
condition = threading.Condition()

# 生产者线程函数,向共享资源中添加数据
def producer():
    for i in range(1, 6):
        with condition:
            shared_resource.append(i)
            print(f"{time.strftime('%H:%M:%S')} 生产: {i}")
            condition.notify()  # 通知消费者线程
            print(f"{time.strftime('%H:%M:%S')} 通知消费者")
            condition.wait()  # 等待消费者线程通知
        time.sleep(1)

# 消费者线程函数,从共享资源中取出数据
def consumer():
    for _ in range(5):
        with condition:
            while not shared_resource:
                print(f"{time.strftime('%H:%M:%S')} 产品不足,通知生产者")
                condition.wait()  # 等待生产者线程通知
            data = shared_resource.pop(0)
            print(f"{time.strftime('%H:%M:%S')} 消费: {data}")
            condition.notify()  # 通知生产者线程
        time.sleep(1)

# 创建生产者和消费者线程
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 have finished")
10:42:43 生产: 1
10:42:43 通知消费者
10:42:43 消费: 1
10:42:45 生产: 2
10:42:45 通知消费者
10:42:45 消费: 2
10:42:46 产品不足,通知生产者
10:42:46 生产: 3
10:42:46 通知消费者
10:42:46 消费: 3
10:42:47 生产: 4
10:42:47 通知消费者
10:42:47 消费: 4
10:42:48 产品不足,通知生产者
10:42:48 生产: 5
10:42:48 通知消费者
10:42:48 消费: 5
All threads have finished

Event(wait、set、clear)

wait方法,线程被阻塞,等待唤醒,wait加参数,表示最多等待多少秒,不加参数表示一直等待

set方法,设置标志位True,wait中的线程被唤醒并执行

clear方法,设置标志位False

import threading

# 共享资源
import time

shared_resource = []
event = threading.Event()

# 生产者线程函数,向共享资源中添加数据
def producer():
    for i in range(1, 6):
        shared_resource.append(i)
        print(f"{time.strftime('%H:%M:%S')} 生产: {i} ")
        event.set()  # 通知消费者线程
        print(f"{time.strftime('%H:%M:%S')} 通知消费者 ")
        event.wait()  # 等待消费者线程通知
        time.sleep(1)

# 消费者线程函数,从共享资源中取出数据
def consumer():
    for _ in range(5):
        while not shared_resource:
            print(f"{time.strftime('%H:%M:%S')} 产品不足,通知生产者 ")
            event.wait()  # 等待生产者线程通知
        data = shared_resource.pop(0)
        print(f"{time.strftime('%H:%M:%S')} 消费: {data} ")
        event.set()  # 通知生产者线程
        time.sleep(1)

# 创建生产者和消费者线程
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 have finished")

运行结果如下:

10:59:35 生产: 1 
10:59:35 通知消费者 
10:59:35 消费: 1 
10:59:36 产品不足,通知生产者 10:59:36 生产: 2 

10:59:36 通知消费者 
10:59:36 消费: 2 
10:59:37 生产: 3 
10:59:37 通知消费者 
10:59:37 消费: 3 
10:59:38 生产: 4 10:59:38 消费: 4 

10:59:38 通知消费者 
10:59:39 生产: 5 10:59:39 消费: 5 

10:59:39 通知消费者 
All threads have finished

Queue

Queue(队列)是 Python 多线程编程中用于线程间通信的重要数据结构。它提供了一种线程安全的方式来在多个线程之间传递数据。Python提供了 queue 模块,其中包含了多种队列类型,包括 Queue(先进先出)LifoQueue(后进先出)PriorityQueue(优先级队列)。最常见的用法是 Queue

# 定义一个共享缓存队列,用于两个线程的数据存放和读取
q = queue.Queue(maxsize=5)    当队列存满了后生产者就不在生产数据,需等消费者消费后再生产
import queue
import threading
import time

# 定义一个共享缓存队列,用于两个线程的数据存放和读取
q = queue.Queue(maxsize=5)


def product():
    count = 1
    while True:
        print(f"{time.strftime('%H:%M:%S')} 生产 item{count}")
        q.put(f'item{count}')
        count += 1
        time.sleep(1)
        print(f"当前产品数:{q.qsize()}")


def customer():
    while True:
        print(f"{time.strftime('%H:%M:%S')} 消费 {q.get()}")
        time.sleep(5)


t0 = threading.Thread(target=product)
t1 = threading.Thread(target=customer)

t0.start()
t1.start()

t0.join()
t1.join()

调试结果:

11:23:40 生产 item1
11:23:40 消费 item1
当前产品数:0
11:23:41 生产 item2
当前产品数:1
11:23:42 生产 item3
当前产品数:2
11:23:43 生产 item4
当前产品数:3
11:23:44 生产 item5
11:23:45 消费 item2
当前产品数:3
11:23:45 生产 item6
当前产品数:4
11:23:46 生产 item7
当前产品数:5
11:23:47 生产 item8
11:23:50 消费 item3
当前产品数:5
11:23:51 生产 item9
11:23:55 消费 item4
当前产品数:5
...
...

Pool

面向对象编程中,创建和销毁对象是很浪费时间的,对于频繁的需要创建和销毁的线程的业务中可以使用线程池来处理,线程池中会默认初始化一定数量的线程对象,有任务来时就分配一个空闲线程去处理,如果线程池无空闲就新建一个线程去处理业务。

from multiprocessing.pool import ThreadPool
import threading
import time

# 创建一个线程锁, 使用线程锁来确保输出的有序性,避免输出内容交织在一起
output_lock = threading.Lock()


# 定义一个函数,用于在线程池中并行执行
def square(x):
    with output_lock:
        print(f"{time.strftime('%H:%M:%S')} {x}*{x}={x * x} ")
    time.sleep(2)


if __name__ == '__main__':
    # 创建一个线程池,设置线程数为4(可以根据需要调整)
    pool = ThreadPool(4)

    for i in range(1, 10):
        pool.apply_async(func=square, args=(i,))

    pool.close()
    pool.join()

调试结果展示,每次有4个线程同时运行 

12:00:12 1*1=1 
12:00:12 2*2=4 
12:00:12 3*3=9 
12:00:12 4*4=16 

12:00:14 5*5=25 
12:00:14 6*6=36 
12:00:14 7*7=49 
12:00:14 8*8=64 

12:00:16 9*9=81 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值