深圳建设监理协会网站,手机网站大全,后台管理网页界面设计,公司网站数据库python 的多线程机制可以的适用场景不适合与计算密集型的#xff0c;因为 GIL 的存在#xff0c;多线程在处理计算密集型时#xff0c;实际上也是串行的#xff0c;因为每个时刻只有一个线程可以获得 GIL#xff0c;但是对于 IO 处理来说#xff0c;不管是网络IO还是文件…python 的多线程机制可以的适用场景不适合与计算密集型的因为 GIL 的存在多线程在处理计算密集型时实际上也是串行的因为每个时刻只有一个线程可以获得 GIL但是对于 IO 处理来说不管是网络IO还是文件读写IO还是数据库IO由于从用户态切换到内核态时此时线程就陷入等待线程让出对应 CPU此时就可以切换到其他线程上继续执行任务总的来说 python 的多线程机制适用于处理 IO 密集型任务。 这里引申出多线程机制的相关应用python 的标准库中已经为我们提供了 threading模块我们可以根据其中的 Thread类 进行线程的相关处理主要就是创建运行阻塞判断是否存活等操作:
Thread(targetfunc, args(), name“myname”)Thread.is_alive()Thread.start()Thread.join()
但 python 的标准库的线程类仅提供了些简单操作更多的线程控制实际上并没有比如针对超时或者对正在运行的线程停掉等而且只要子线程 start() 后其运行就脱离控制了即使 join(timeout10) 设置也只是针对 is_alive() 进行属性的更改这一点 golang 就在 goroutine 中做得很好这里不是讨论重点。 接下来我们就来看看线程类的使用吧。
1.start()后立即join()操作
很多刚使用 python 的人可能在 start() 后就立即 join()这里会有问题具体怎样呢我们看看示例
import time, datetime
import threading
import sysdef foo(sleep2):print(当前thread: [{}].format(threading.current_thread().name))time.sleep(sleep)print(thread: [{}] end..format(threading.current_thread().name))def multiThread_v1():version1: 多个线程start后再join:return:print([{}] [{}] start....format(datetime.datetime.now(), sys._getframe().f_code.co_name))t1 threading.Thread(targetfoo, namet1)t2 threading.Thread(targetfoo, namet2)t3 threading.Thread(targetfoo, namet3)t4 threading.Thread(targetfoo, namet4)t5 threading.Thread(targetfoo, namet5)t1.start()t1.join()t2.start()t2.join()t3.start()t3.join()t4.start()t4.join()t5.start()t5.join()print([{}] [{}] end....format(datetime.datetime.now(), sys._getframe().f_code.co_name))if __name__ __main__:multiThread_v1()以下是运行结果
[2023-04-13 10:40:55.820157] [multiThread_v1] start...
当前thread: [t1]
thread: [t1] end.
当前thread: [t2]
thread: [t2] end.
当前thread: [t3]
thread: [t3] end.
当前thread: [t4]
thread: [t4] end.
当前thread: [t5]
thread: [t5] end.
[2023-04-13 10:41:05.833481] [multiThread_v1] end...可以看到本来我们创建5个子线程想着可以并发跑实际上是串行的那多线程还有啥意义呢还不如主线程里串行执行。
这里就要主要到 join() 的作用了当 start() 后子线程就开始运行了我们通过调用 join()这里就是阻塞主线程告诉主线程你得等我子线程运行完才能执行接下来的逻辑多个子线程都这样能不是串行执行了吗。
2.常见的应用
下面介绍一种常见的多线程的应用通过下面的编码实现多线程执行并发的效果
def multiThread_v3():print([{}] [{}] start....format(datetime.datetime.now(), sys._getframe().f_code.co_name))t_list []for i in range(5):arg 5 if i % 2 1 else 4t threading.Thread(targetfoo, args(arg,), namethread_str(i))t_list.append(t)for t in t_list:t.start()for t in t_list:t.join()print([{}] [{}] end....format(datetime.datetime.now(), sys._getframe().f_code.co_name))if __name__ __main__:multiThread_v3()以下是执行结果
[2023-04-13 10:46:28.393077] [multiThread_v3] start...
当前thread: [thread_0]
当前thread: [thread_1]
当前thread: [thread_2]
当前thread: [thread_3]
当前thread: [thread_4]
thread: [thread_4] end.thread: [thread_0] end.thread: [thread_2] end.thread: [thread_1] end.
thread: [thread_3] end.
[2023-04-13 10:46:33.395467] [multiThread_v3] end...代码中通过设置几个sleep 5秒几个sleep 4秒模拟不同的处理耗时可以看到从开始到结束线程单个时间总和应该是 4545422秒实际上只运行5秒就全部结束了我们还是回到 start() 和 join() 的功能上来分析start() 后都在跑子线程通过 join(), 阻塞主线程由于子线程都已经在运行实际上的耗时取决于耗时最长的那个也就是 sleep 5秒的的线程所以 thread_0/2/4几乎同时结束运行4秒接着是thread_3/5运行5秒实际在业务时实现时我们并不能预知耗时情况比如涉及到网络抖动、磁盘IO等所以通过遍历 join() 就更合理点。
补充
thread中join()函数的作用如果thread是某个子线程则调用thread.join()的作用是确保thread子线程执行完毕后才能执行下一个线程。下面第一个例子中没有调用join()函数故没有这个限制所有线程执行顺序都不定。
第二个例子中在每个子线程启动start()后马上调用了join()函数这就确保了对于每一个子线程必须等它执行完毕后才能执行下一个程序故子线程是按顺序执行的且主线程中的print()方法是在所有的子线程执行完毕后才执行。
第三个例子中对于子线程启动start()后没有马上调用join()函数故子线程的执行顺序是不确定的但是主线程中的print()前调用了每个子线程的join()函数故print()要在所有的子线程执行完毕后才能执行。
1没有使用join()函数线程执行顺序不定主线程可能在所有子线程执行完之前就执行了
2修改部分代码如下每次启动子线程后调用一次join()函数可以看出线程按顺序执行且主线程在所有子线程执行完之 后才执行。
3修改部分代码如下可以看出子线程执行顺序不定但是主线程是在所有子线程执行完毕之后才执行的。
参考文章
python标准库threading 聊聊python的标准库 threading 的中 start 和 join 的使用注意事项 Python多线程:Threading中join()函数的理解 Python 多线程