Python用threading实现多线程详解
发布时间 - 2026-01-10 22:50:23 点击率:次多线程

多线程是个提高程序运行效率的好办法,本来要顺序执行的程序现在可以并行执行,可想而知效率要提高很多。但是多线程也不是能提高所有程序的效率。程序的两个极端是‘CPU 密集型'和‘I/O 密集型'两种,多线程技术比较适用于后者,因为在串行结构中当你去读写磁盘或者网络通信的时候 CPU 是闲着的,毕竟网络比磁盘要慢几个数量级,磁盘比内存慢几个数量级,内存又比 CPU 慢几个数量级。多线程技术就可以同时执行,比如你的程序需要发送 N 个 http 数据包(10 秒),还需要将文件从一个位置复制到另一个位置(20 秒),然后还需要统计另一个文件中'hello,world'字符串的出现次数(4 秒),现在一共是要用 34 秒。但是因为这些操作之间没有关联,所以可以写成多线程程序,几乎只需要 20 秒就完成了。这是针对 I/O 密集型的,如果是 CPU 密集型的就不行了。比如我的程序要计算 1000 的阶乘(10 秒),还要计算 100000 的累加(5 秒),那么即使程序是并行的,还是会要用 15 秒,甚至更多。因为当程序使用 CPU 的时候 CPU 是通过轮转来执行的,IO 密集型的程序可以在 IO 的同时用 CPU 计算,但是这里的 CPU 密集型就只能先执行一会儿线程 1 再执行一会儿线程 2。所以就需要 15 秒,甚至会更多,因为 CPU 在切换的时候需要耗时。解决 CPU 密集型程序的多线程问题就是 CPU 的事情了,比如 Intel 的超线程技术,可以在同一个核心上真正的并行两个线程,所以称之为‘双核四线程'或者‘四核八线程',我们这里具体的先不谈,谈我也不知道。
Python 骗人
说了这么多多线程的好处,但是其实 Python 不支持真正意义上的多线程编程。在 Python 中有一个叫做 GIL 的东西,中文是 全局解释器 ,这东西控制了 Python,让 Python 只能同时运行一个线程。相当于说真正意义上的多线程是由 CPU 来控制的,Python 中的多线程由 GIL 控制。如果有一个 CPU 密集型程序,用 C 语言写的,运行在一个四核处理器上,采用多线程技术的话最多可以获得 4 倍的效率提升,但是如果用 Python 写的话并不会有提高,甚至会变慢,因为线程切换的问题。所以 Python 多线程相对更加适合写 I/O 密集型程序,再说了真正的对效率要求很高的 CPU 密集型程序都用 C/C++ 去了。
第一个多线程
Python 中多线程的库一般用thread和threading这两个,thread不推荐新手和一般人使用,threading模块就相当够用了。
有一个程序,如下。两个循环,分别休眠 3 秒和 5 秒,串行执行的话需要 8 秒。
#!/usr/bin/env python # coding=utf-8 import time def sleep_3(): time.sleep(3) def sleep_5(): time.sleep(5) if __name__ == '__main__': start_time = time.time() print 'start sleep 3' sleep_3() print 'start sleep 5' sleep_5() end_time = time.time() print str(end_time - start_time) + ' s'
输出是这样的
start sleep 3 start sleep 5 8.00100016594 s
然后我们对它进行修改,使其变成多线程程序,虽然改动没有几行。首先引入了 threading 的库,然后实例化一个 threading.Thread 对象,将一个函数传进构造方法就行了。然后调用 Thread 的 start 方法开始一个线程。join() 方法可以等待该线程结束,就像我下面用的,如果我不加那两个等待线程结束的代码,那么就会直接执行输出时间的语句,这样一来统计的时间就不对了。
#!/usr/bin/env python # coding=utf-8 import time import threading # 引入threading def sleep_3(): time.sleep(3) def sleep_5(): time.sleep(5) if __name__ == '__main__': start_time = time.time() print 'start sleep 3' thread_1 = threading.Thread(target=sleep_3) # 实例化一个线程对象,使线程执行这个函数 thread_1.start() # 启动这个线程 print 'start sleep 5' thread_2 = threading.Thread(target=sleep_5) # 实例化一个线程对象,使线程执行这个函数 thread_2.start() # 启动这个线程 thread_1.join() # 等待thread_1结束 thread_2.join() # 等待thread_2结束 end_time = time.time() print str(end_time - start_time) + ' s'
执行结果是这样的
start sleep 3 start sleep 5 5.00099992752 s
daemon 守护线程
在我们理解中守护线程应该是很重要的,类比于 Linux 中的守护进程。但是在threading.Thread中偏偏不是。
如果把一个线程设置为守护线程,就表示这个线程是不重要的,进程退出的时候不需要等待这个线程执行完成。 ---------《Python 核心编程 第三版》
在 Thread 对象中默认所有线程都是非守护线程,这里有两个例子说明区别。这段代码执行的时候就没指定my_thread的daemon属性,所以默认为非守护,所以进程等待他结束。最后就可以看到 100 个 hello,world
#!/usr/bin/env python # coding=utf-8 import threading def hello_world(): for i in range(100): print 'hello,world' if __name__ == '__main__': my_thread = threading.Thread(target=hello_world) my_thread.start()
这里设置了my_thread为守护线程,所以进程直接就退出了,并没有等待他的结束,所以我们看不到 100 个 hello,world 只有几个而已。甚至还会抛出一个异常告诉我们有线程没结束。
#!/usr/bin/env python # coding=utf-8 import threading def hello_world(): for i in range(100): print 'hello,world' if __name__ == '__main__': my_thread = threading.Thread(target=hello_world) my_thread.daemon = True # 设置了标志位True my_thread.start()
传个参数
之前的代码都是直接执行一段代码,没有过参数的传递,那么怎么传递参数呢?其实还是很简单的。threading.Thread(target=hello_world, args=('hello,', 'world'))就可以了。args 后面跟的是一个元组,如果没有参数可以不写,如果有参数就直接在元组里按顺序添加就行了。
#!/usr/bin/env python
# coding=utf-8
import threading
def hello_world(str_1, str_2):
for i in range(10):
print str_1 + str_2
if __name__ == '__main__':
my_thread = threading.Thread(target=hello_world, args=('hello,', 'world')) # 这里传递参数
my_thread.start()
再来个多线程
threading 有三种创建 Thread 对象的方式,但是一般只会用到两种,一种是上面0X02说的传个函数进去,另一种就是这里说的继承threading.Thread。在这儿我们自己定义了两个类,类里重写了 run() 方法,也就是调用 start() 之后执行的代码,开启线程就和之前开启是一样的。之前的方式更面向过程,这个更面向对象。
#!/usr/bin/env python # coding=utf-8 import threading class MyThreadHello(threading.Thread): def run(self): for i in range(100): print 'hello' class MyThreadWorld(threading.Thread): def run(self): for i in range(100): print 'world' if __name__ == '__main__': thread_hello = MyThreadHello() thread_world = MyThreadWorld() thread_hello.start() thread_world.start()
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。
# python实现多线程
# threading多线程
# python
# threading
# Python中多线程thread与threading的实现方法
# python基于queue和threading实现多线程下载实例
# python使用threading获取线程函数返回值的实现方法
# Python 使用threading+Queue实现线程池示例
# Python线程协作threading.Condition实现过程解析
# Python3 socket即时通讯脚本实现代码实例(threading多线程)
# python中threading和queue库实现多线程编程
# Python中threading库实现线程锁与释放锁
# Python threading和Thread模块及线程的实现
# 多线程
# 几个
# 就可以
# 是这样
# 两种
# 要用
# 会儿
# 有一个
# 的是
# 都是
# 这是
# 就行了
# 就会
# 是个
# 会有
# 去了
# 出了
# 第一个
# 最多
# 不需要
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
千问怎样用提示词获取健康建议_千问健康类提示词注意事项【指南】
Laravel怎么连接多个数据库_Laravel多数据库连接配置
高性能网站服务器配置指南:安全稳定与高效建站核心方案
Swift中swift中的switch 语句
如何制作新型网站程序文件,新型止水鱼鳞网要拆除吗?
如何用PHP快速搭建高效网站?分步指南
Java类加载基本过程详细介绍
高端云建站费用究竟需要多少预算?
Laravel怎么在Blade中安全地输出原始HTML内容
Laravel如何使用集合(Collections)进行数据处理_Laravel Collection常用方法与技巧
如何在IIS中配置站点IP、端口及主机头?
Laravel怎么生成二维码图片_Laravel集成Simple-QrCode扩展包与参数设置【实战】
Laravel怎么实现搜索高亮功能_Laravel结合Scout与Algolia全文检索【实战】
Laravel如何使用Socialite实现第三方登录?(微信/GitHub示例)
Laravel怎么实现软删除SoftDeletes_Laravel模型回收站功能与数据恢复【步骤】
Laravel如何实现事件和监听器?(Event & Listener实战)
如何在不使用负向后查找的情况下匹配特定条件前的换行符
微信小程序 HTTPS报错整理常见问题及解决方案
独立制作一个网站多少钱,建立网站需要花多少钱?
实例解析Array和String方法
浅析上传头像示例及其注意事项
logo在线制作免费网站在线制作好吗,DW网页制作时,如何在网页标题前加上logo?
原生JS获取元素集合的子元素宽度实例
Bootstrap整体框架之JavaScript插件架构
浅谈javascript alert和confirm的美化
如何在IIS服务器上快速部署高效网站?
bootstrap日历插件datetimepicker使用方法
HTML透明颜色代码怎么让下拉菜单透明_下拉菜单透明背景指南【技巧】
西安市网站制作公司,哪个相亲网站比较好?西安比较好的相亲网站?
Laravel如何将应用部署到生产服务器_Laravel生产环境部署流程
如何在宝塔面板创建新站点?
制作公司内部网站有哪些,内网如何建网站?
如何破解联通资金短缺导致的基站建设难题?
如何快速配置高效服务器建站软件?
如何利用DOS批处理实现定时关机操作详解
php在windows下怎么调试_phpwindows环境调试操作说明【操作】
高端建站三要素:定制模板、企业官网与响应式设计优化
昵图网官方站入口 昵图网素材图库官网入口
网站视频制作书签怎么做,ie浏览器怎么将网站固定在书签工具栏?
Laravel怎么使用Intervention Image库处理图片上传和缩放
韩国服务器如何优化跨境访问实现高效连接?
重庆市网站制作公司,重庆招聘网站哪个好?
网站制作价目表怎么做,珍爱网婚介费用多少?
大连网站制作公司哪家好一点,大连买房网站哪个好?
如何用VPS主机快速搭建个人网站?
悟空浏览器如何设置小说背景色_悟空浏览器背景色设置【方法】
Laravel如何配置和使用缓存?(Redis代码示例)
Laravel如何配置中间件Middleware_Laravel自定义中间件拦截请求与权限校验【步骤】
javascript和jQuery中的AJAX技术详解【包含AJAX各种跨域技术】
Win11应用商店下载慢怎么办 Win11更改DNS提速下载【修复】

