人人都能学会的 Python 多线程指南( 二 )


thread2 = threading.Thread(target=do_something)
thread1.start()
thread2.start()
finish = time.perf_counter()
print(f"全部任务执行完成 , 耗时 {round(finish - start,2)} 秒")
执行上面的代码 , 结果如下
-> 线程启动
-> 线程启动
全部任务执行完成 , 耗时 0.0 秒
-> 线程结束
-> 线程结束
可以看到 , 两个子线程确实同时启动 , 但是主线程并未等待两个子线程执行完毕就直接结束 。
为了解决这个问题 , 我们可以使用threading.join()方法 , 意思是在子线程完成运行之前 , 这个子线程的父线程将一直被阻塞
换成人话就是让主线程挂起 , 等待所有子线程结束再执行 , 体现到代码上也很简单 , 只需要添加两行即可
import time
import threading
start = time.perf_counter()
def do_something():
print("-> 线程启动")
time.sleep(1)
print("-> 线程结束")
thread1 = threading.Thread(target=do_something)
thread2 = threading.Thread(target=do_something)
thread1.start()
thread2.start()
thread1.join()
thread2.join()
finish = time.perf_counter()
print(f"全部任务执行完成 , 耗时 {round(finish - start,2)} 秒")
运行结果如下 , 全部代码在1秒内运行完毕
-> 线程启动
-> 线程启动
-> 线程结束
-> 线程结束
全部任务执行完成 , 耗时 1.01 秒
至此 , 我们就得到了第一个有效的多线程代码 , 相信你也能大致明白threading的基本使用流程 。
传递参数
现在来看看如何在多线程之间传递参数 , 让我们升级代码:do_something函数来接受一个参数 , 控制他睡眠等待的时间
def do_something(num):
print(f"-> 线程{num} 启动 , 睡眠 {num} 秒")
time.sleep(num)
print(f"-> 线程{num} 结束")
在 threading 中 , 创建线程时可以使用 args 来传递参数 , 例如现在接收一个参数 , 则上一小节的代码可以如下修改
import time
import threading
start = time.perf_counter()
def do_something(num):
print(f"-> 线程{num} 启动 , 睡眠 {num} 秒")
time.sleep(num)
print(f"-> 线程{num} 结束")
thread1 = threading.Thread(target=do_something,args = [1])
thread2 = threading.Thread(target=do_something,args = [2])
thread1.start()
thread2.start()
thread1.join()
thread2.join()
finish = time.perf_counter()
print(f"全部任务执行完成 , 耗时 {round(finish - start,2)} 秒")
这段代码中 , 我分别让两个线程等待1、2秒 , 运行结果显然应该是2秒
-> 线程1 启动 , 睡眠 1 秒
-> 线程2 启动 , 睡眠 2 秒
-> 线程1 结束
-> 线程2 结束
全部任务执行完成 , 耗时 2.01 秒
如果你的线程函数需要更多的参数 , 只需要依次向args中追加即可 。
简化代码
上面的案例中 , 我们仅开启了两个线程 , 如果是更多个线程的话 , 再依次重复定义、启动就会显得十分繁琐 , 此时我们可以使用循环来处理 。
例如开启10个线程 , 依次睡眠1-10秒 , 可以先创建一个 list 用于存储每个线程 , 接着利用循环依次创建线程 , 启动后追加到刚刚创建的 list 中 , 之后再依次等待每个线程执行完毕 , 代码如下
import time
import threading
start = time.perf_counter()
def do_something(num):
print(f"-> 线程{num} 启动 , 睡眠 {num} 秒")
time.sleep(num)
print(f"-> 线程{num} 结束")
thread_list = []
for i in range(1,11):
thread = threading.Thread(target=do_something, args=[i])
thread.start()
thread_list.append(thread)
for t in thread_list:
t.join()
finish = time.perf_counter()
print(f"全部任务执行完成 , 耗时 {round(finish - start,2)} 秒")
结果是显然的 , 虽然我们执行了十次do_something , 每次用时1-10秒 , 但总耗时应该为10秒