全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

Python用threading实现多线程详解

多线程

多线程是个提高程序运行效率的好办法,本来要顺序执行的程序现在可以并行执行,可想而知效率要提高很多。但是多线程也不是能提高所有程序的效率。程序的两个极端是‘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模块及线程的实现  # 多线程  # 几个  # 就可以  # 是这样  # 两种  # 要用  # 会儿  # 有一个  # 的是  # 都是  # 这是  # 就行了  # 就会  # 是个  # 会有  # 去了  # 出了  # 第一个  # 最多  # 不需要 


相关文章: 如何快速生成专业多端适配建站电话?  哪家制作企业网站好,开办像阿里巴巴那样的网络公司和网站要怎么做?  网站制作和推广的区别,想自己建立一个网站做推广,有什么快捷方法马上做好一个网站?  c# 在ASP.NET Core中管理和取消后台任务  教学网站制作软件,学习*后期制作的网站有哪些?  红河网站制作公司,红河事业单位身份证如何上传?  大连网站制作公司哪家好一点,大连买房网站哪个好?  网站设计制作公司地址,网站建设比较好的公司都有哪些?  高防服务器:AI智能防御DDoS攻击与数据安全保障  如何用AWS免费套餐快速搭建高效网站?  如何高效利用亚马逊云主机搭建企业网站?  如何在宝塔面板中创建新站点?  建站主机如何选?高性价比方案全解析  图册素材网站设计制作软件,图册的导出方式有几种?  ,想在网上投简历,哪几个网站比较好?  如何高效利用200m空间完成建站?  seo网站制作优化,网站SEO优化步骤有哪些?  香港服务器WordPress建站指南:SEO优化与高效部署策略  高性价比服务器租赁——企业级配置与24小时运维服务  C++用Dijkstra(迪杰斯特拉)算法求最短路径  移动端手机网站制作软件,掌上时代,移动端网站的谷歌SEO该如何做?  广东专业制作网站有哪些,广东省能源集团有限公司官网?  历史网站制作软件,华为如何找回被删除的网站?  如何通过二级域名建站提升品牌影响力?  制作农业网站的软件,比较好的农业网站推荐一下?  杭州银行网站设计制作流程,杭州银行怎么开通认证方式?  ,制作一个手机app网站要多少钱?  北京企业网站设计制作公司,北京铁路集团官方网站?  香港代理服务器配置指南:高匿IP选择、跨境加速与SEO优化技巧  音乐网站服务器如何优化API响应速度?  javascript中对象的定义、使用以及对象和原型链操作小结  建站之星logo尺寸如何设置最合适?  家庭建站与云服务器建站,如何选择更优?  如何在阿里云域名上完成建站全流程?  网站设计制作企业有哪些,抖音官网主页怎么设置?  长春网站建设制作公司,长春的网络公司怎么样主要是能做网站的?  如何用wdcp快速搭建高效网站?  网站制作壁纸教程视频,电脑壁纸网站?  哈尔滨网站建设策划,哈尔滨电工证查询网站?  建站之星3.0如何解决常见操作问题?  公司门户网站制作流程,华为官网怎么做?  ,南京靠谱的征婚网站?  专业网站建设制作报价,网页设计制作要考什么证?  建站之星价格显示格式升级,你的预算足够吗?  如何快速搭建虚拟主机网站?新手必看指南  北京的网站制作公司有哪些,哪个视频网站最好?  如何快速搭建安全的FTP站点?  建站之星展会模版如何一键下载生成?  魔毅自助建站系统:模板定制与SEO优化一键生成指南  建站之星多图banner生成与模板自定义指南 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。