参考文章
python线程池 ThreadPoolExecutor 的用法及实战
创建 threading.Thread
threading.Thread 构造方法:
threading.Thread(group=None, target=None, name=None,args=(), kwargs=None, *, daemon=None
- group:应为None,预留给将来扩展ThreadGroup时使用类实现。
- target:要调用的函数
- name:线程名,默认是Thread-1,Thread-2… Thread-N
- args:函数的可变参数
- kwargs:函数的关键词参数
- daemon:是否是守护进程,True 是,False 不是
import random
import threading
import time
def doing(person, task):
thread_name = threading.current_thread().name
print("threadName=%s : %s start %s " % (thread_name, person, task))
time.sleep(random.randrange(start=1, stop=5))
print("threadName=%s : %s end %s " % (thread_name, person, task))
def test1():
for i in range(0, 3):
my_thread = threading.Thread(target=doing, args=("%d 号工人" % i, "%d 号任务" % i))
my_thread.start()
if __name__ == "__main__":
test1()
运行结果:
threadName=Thread-1 : 0 号工人 start 0 号任务
threadName=Thread-2 : 1 号工人 start 1 号任务
threadName=Thread-3 : 2 号工人 start 2 号任务
threadName=Thread-2 : 1 号工人 end 1 号任务
threadName=Thread-1 : 0 号工人 end 0 号任务
threadName=Thread-3 : 2 号工人 end 2 号任务
继承 threading.Thread
import random
import threading
import time
class DoingThread(threading.Thread):
def __init__(self, person, task):
super(DoingThread, self).__init__()
self.person = person
self.task = task
def run(self):
thread_name = threading.current_thread().name
print("threadName=%s : %s start %s " % (thread_name, self.person, self.task))
time.sleep(random.randrange(start=1, stop=5))
print("threadName=%s : %s end %s " % (thread_name, self.person, self.task))
def test2():
for i in range(0, 3):
my_thread = DoingThread("%d 号工人" % i, "%d 号任务" % i)
my_thread.start()
if __name__ == "__main__":
test2()
运行结果:
threadName=Thread-1 : 0 号工人 start 0 号任务
threadName=Thread-2 : 1 号工人 start 1 号任务
threadName=Thread-3 : 2 号工人 start 2 号任务
threadName=Thread-2 : 1 号工人 end 1 号任务
threadName=Thread-3 : 2 号工人 end 2 号任务
threadName=Thread-1 : 0 号工人 end 0 号任务
线程池 concurrent.futures
从Python3.2开始,标准库为我们提供了 concurrent.futures 模块,它提供了 ThreadPoolExecutor (线程池)
相比 threading 等模块,该模块通过 submit 返回的是一个 future 对象,它是一个未来可期的对象,通过它可以获取某线程执行的状态和返回值
import random
import time
import threading
from concurrent.futures import ThreadPoolExecutor
def doing(person, task):
thread_name = threading.current_thread().name
print("threadName=%s : %s start %s " % (thread_name, person, task))
time.sleep(random.randrange(start=1, stop=5))
print("threadName=%s : %s end %s " % (thread_name, person, task))
return thread_name
def test3():
# 创建一个最大容纳数量为2的线程池
with ThreadPoolExecutor(max_workers=3) as executor:
items = []
for i in range(0, 3):
item = executor.submit(doing, "%d 号工人" % i, "%d 号任务" % i)
items.append(item)
results = []
for item in items:
results.append(item.result())
print(results)
if __name__ == "__main__":
test3()
运行结果:
threadName=ThreadPoolExecutor-0_0 : 0 号工人 start 0 号任务
threadName=ThreadPoolExecutor-0_1 : 1 号工人 start 1 号任务
threadName=ThreadPoolExecutor-0_2 : 2 号工人 start 2 号任务
threadName=ThreadPoolExecutor-0_0 : 0 号工人 end 0 号任务
threadName=ThreadPoolExecutor-0_2 : 2 号工人 end 2 号任务
threadName=ThreadPoolExecutor-0_1 : 1 号工人 end 1 号任务
['ThreadPoolExecutor-0_0', 'ThreadPoolExecutor-0_1', 'ThreadPoolExecutor-0_2']
future.result(timeout=None) : 获取线程的运行结果,如果没有执行完成,则一直等待(或等待timeout),直到有结果。
所有上面的结果顺序和执行顺序一样,即使ThreadPoolExecutor-0_2 比 ThreadPoolExecutor-0_1 更早的结束。
as_completed
谁执行的快就获取谁的结果。当线程池中有子线程中的执行结束,马上返回该线程,用 result() 获取返回结果,不要像上面一样按执行顺序获取结果、
def test3():
# 创建一个最大容纳数量为2的线程池
with ThreadPoolExecutor(max_workers=3) as executor:
items = []
for i in range(0, 3):
item = executor.submit(doing, "%d 号工人" % i, "%d 号任务" % i)
items.append(item)
results = []
# for item in items:
for item in as_completed(items):
results.append(item.result())
print(results)
运行结果:
threadName=ThreadPoolExecutor-0_0 : 0 号工人 start 0 号任务
threadName=ThreadPoolExecutor-0_1 : 1 号工人 start 1 号任务
threadName=ThreadPoolExecutor-0_2 : 2 号工人 start 2 号任务
threadName=ThreadPoolExecutor-0_1 : 1 号工人 end 1 号任务
threadName=ThreadPoolExecutor-0_0 : 0 号工人 end 0 号任务
threadName=ThreadPoolExecutor-0_2 : 2 号工人 end 2 号任务
['ThreadPoolExecutor-0_1', 'ThreadPoolExecutor-0_0', 'ThreadPoolExecutor-0_2']