本文将和大家一起探讨python的多线程并发编程(下篇),使用内置基本库threading来实现并发,先通过官方来简单使用这个模块。先打好基础,能够有个基本的用法与认知,后续文章,我们再进行详细使用。
本文为python并发编程的第九篇,上一篇文章地址如下:
python:并发编程(八)_Lion King的博客-CSDN博客
下一篇文章地址如下:
python:并发编程(十)_Lion King的博客-CSDN博客
import threading
# 定义一个全局变量,用于控制打印的数字
num = 0
# 创建一个锁对象
lock = threading.Lock()
# 偶数线程函数
def print_even():
global num
while num < 10:
# 获取锁
lock.acquire()
if num % 2 == 0:
print("Even:", num)
num += 1
# 释放锁
lock.release()
# 奇数线程函数
def print_odd():
global num
while num < 10:
# 获取锁
lock.acquire()
if num % 2 != 0:
print("Odd:", num)
num += 1
# 释放锁
lock.release()
# 创建偶数线程
even_thread = threading.Thread(target=print_even)
# 创建奇数线程
odd_thread = threading.Thread(target=print_odd)
# 启动线程
even_thread.start()
odd_thread.start()
# 等待线程结束
even_thread.join()
odd_thread.join()
这个程序创建了两个线程,一个线程负责打印偶数,另一个线程负责打印奇数。使用全局变量num
来控制打印的数字,初始值为0。通过获取锁来保证只有一个线程能够打印数字,并在打印后释放锁,以实现按顺序打印偶数和奇数。最后,使用join()
方法等待两个线程执行完成。
运行这个程序,你将会看到按顺序打印出0到9的偶数和奇数。
import threading
# 创建一个信号量,初始值为0
semaphore_A = threading.Semaphore(1)
semaphore_B = threading.Semaphore(0)
semaphore_C = threading.Semaphore(0)
# 打印A的线程函数
def print_A():
for _ in range(10):
# 获取A的信号量,允许打印A
semaphore_A.acquire()
print("A", end="")
# 发送信号量给B,允许打印B
semaphore_B.release()
# 打印B的线程函数
def print_B():
for _ in range(10):
# 获取B的信号量,允许打印B
semaphore_B.acquire()
print("B", end="")
# 发送信号量给C,允许打印C
semaphore_C.release()
# 打印C的线程函数
def print_C():
for _ in range(10):
# 获取C的信号量,允许打印C
semaphore_C.acquire()
print("C", end="")
# 发送信号量给A,允许打印A
semaphore_A.release()
# 创建三个线程
thread_A = threading.Thread(target=print_A)
thread_B = threading.Thread(target=print_B)
thread_C = threading.Thread(target=print_C)
# 启动线程
thread_A.start()
thread_B.start()
thread_C.start()
# 等待线程结束
thread_A.join()
thread_B.join()
thread_C.join()
这个程序创建了三个线程,分别用于打印字母A、B和C。通过使用信号量来控制线程的执行顺序。初始时,A线程获得信号量semaphore_A
,允许打印A,然后它将信号量semaphore_B
释放,允许B线程执行。B线程打印B后,释放信号量semaphore_C
,允许C线程执行。C线程打印C后,释放信号量semaphore_A
,允许A线程执行,从而形成ABCABC...的循环打印。
运行这个程序,你将会看到按顺序循环打印出ABCABC...,每个字母重复打印10次。
import threading
import queue
# 用于输入数字的线程函数
def input_number():
while True:
number = input("请输入一个数字(输入exit退出):")
if number == "exit":
break
else:
# 将输入的数字转换为整数,并发送给计算线程
calculation_thread.queue.put(int(number))
# 用于计算数字平方并输出结果的线程函数
def calculate_square():
while True:
number = calculation_thread.queue.get()
square = number ** 2
print(f"{number} 的平方是 {square}")
# 创建一个线程间通信的队列
calculation_thread = threading.Thread(target=calculate_square)
calculation_thread.queue = queue.Queue()
# 创建输入数字的线程
input_thread = threading.Thread(target=input_number)
# 启动两个线程
calculation_thread.start()
input_thread.start()
# 等待输入线程结束
input_thread.join()
# 清空队列中的剩余元素
while not calculation_thread.queue.empty():
number = calculation_thread.queue.get()
square = number ** 2
print(f"{number} 的平方是 {square}")
# 等待计算线程结束
calculation_thread.join()
这个程序创建了两个线程,一个用于输入数字,另一个用于计算数字的平方并输出结果。输入线程通过用户输入数字,并将其转换为整数后发送给计算线程。计算线程从队列中获取数字,并计算其平方后输出结果。当用户输入"exit"时,输入线程退出,然后程序等待队列中剩余的计算任务完成,并输出结果。
运行这个程序,你可以多次输入数字,程序将会实时计算并输出数字的平方。当你输入"exit"时,程序会等待队列中的剩余计算任务完成,并输出结果。
使用Thread
类创建线程对象,将要执行的函数作为参数传递给线程对象的target
参数。
使用线程对象的start
方法启动线程,该方法会自动调用线程函数。
使用锁、条件、信号量等同步机制来控制线程的执行顺序和访问共享资源的安全性。
可以使用队列、事件、管道等机制实现线程间的通信,以便在不同线程之间传递数据或控制信息。
线程可以通过设置标志位或调用Thread
类的stop
方法来终止线程的执行。然而,直接终止线程可能导致资源泄漏或数据不一致,因此最好通过合理的设计和协调使线程正常退出。
使用join
方法可以等待线程执行完成,主线程可以调用线程对象的join
方法来等待子线程的结束。
可以使用Thread
类的setDaemon
方法设置线程的优先级。
可以使用try-except
语句捕获线程执行过程中可能抛出的异常,确保程序的健壮性。
可以给线程对象设置一个有意义的名称,方便调试和识别不同的线程。
在创建线程时要考虑系统的资源限制,过多的线程可能会导致资源竞争和性能下降。