Python3中两种基本的多线程方式

Python3中两种基本的多线程方式

Posted by G.h. Qi on July 13, 2024

前言

预计阅读时长:。。 min
原文链接:Python3中两种基本的多线程方式
原作者:Gh Qi,如需引用转载,请注明来源。

写在前面

1. 多线程与多进程

2. 两种简单的多线程编程实现方式

2.1 使用threading库进行多线程编程

2.2 使用concurrent库进行多线程编程

executor.map()函数

executor.mapconcurrent.futures 模块中 ThreadPoolExecutorProcessPoolExecutor 的一个便捷方法,它用于将一个函数应用于可迭代对象的每个元素上,并收集结果。下面是 executor.map 的参数意义:

func: 要应用于每个输入项的函数。
*iterables: 一个或多个可迭代对象,executor.map 将 func 应用于这些可迭代对象的元素。

用人话讲:

executor.map(func,*iterables)的第二个参数中的iterables是一个列表,里面存放的是func函数的参数,func函数需要几个参数,列表iterables中就有几个元素,每个元素都是一个包含了所有线程所需的该参数值的元组。

例如: 定义一个求两数之和函数:sum(a,b). 我想求1和2的和,3和4的和,5和6的和,这件事安排给3个线程来干。参数可以写为:

data_to_process = [(1, 2), (3, 4), (5, 6)]

要想使用executor.map(func,*iterables),需作如下转换:

*zip(*data_to_process)  # 第二个参数

print(*zip(*data_to_process))

(1, 3, 5) (2, 4, 6)

iterables 里面给定参数组数可以低于max_workers,那么并不是所有的线程都会被分配工作。线程池中的线程会等待直到有任务可做,或者直到所有任务完成。当然也可以高于max_workers,那就只能排队干活了。

executor.map 返回的是一个可迭代对象,它按顺序提供了 func 应用于每个输入项的结果。在 Python 3.7 之前,它返回一个列表;从 Python 3.7 开始,它返回一个 concurrent.futures._base._as_completed 对象,这个对象是可迭代的,但不是列表。

<generator object Executor.map.<locals>.result_iterator at 0x000001FB535D72E0>

要打印每个线程执行函数的输出结果,可以迭代 executor.map 返回的对象;也可以使用list()将其转化为一个列表。

# 方法1
with ThreadPoolExecutor(max_workers=5) as executor:
    results = executor.map(process_data, *zip(*data_to_process))
print(results)
for result in results:
        print(result)

# 方式2        
with ThreadPoolExecutor(max_workers=5) as executor:
    results = list(executor.map(process_data, *zip(*data_to_process)))
print(results)

输出是:

<generator object Executor.map.<locals>.result_iterator at 0x000002A7435F3790>
3
7
11

[3, 7, 11]

完整代码:

from concurrent.futures import ThreadPoolExecutor

# 定义要执行的函数
def process_data(arg1, arg2):
    # 这里可以是任何需要两个参数的逻辑
    return arg1 + arg2

# 创建数据列表,每个元素是一个包含两个参数的元组
# 我想求1和2的和,3和4的和,5和6的和,这件事安排给3个线程来干
data_to_process = [(1, 2), (3, 4), (5, 6)]

# 创建线程池(最大线程数不超过5各)
with ThreadPoolExecutor(max_workers=5) as executor:
    # 使用 zip 将 data_to_process 中的元组解包为两个参数
    results = list(executor.map(process_data, *zip(*data_to_process)))
    
# 打印每个线程的输出结果
for result in results:
    print(result)

小结

参考资料