首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

Python多线程的基本套路你知道么?

概述

python对多线程的支持

先看一个概念:

官方描述:In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple native threads from executing Python bytecodes at once. This lock is necessary mainly because CPython’s memory management is not thread-safe. (However, since the GIL exists, other features have grown to depend on the guarantees that it enforces.)

由于GIL的存在,python其实无法利用多处理器的优势,任意时刻只会有一个线程运行在解释器中,也就是大计算量的程序在python中通过多线程处理其实不见得会变快。但是IO密集型程序可以很好地利用多线程,比如用python开发一个rest客户端程序,如果单线程实现,假如发送一个http请求服务器端需要耗费5s来处理,串行发送1000个就需要5000s左右;但是开1000个线程,就可以同时发送1000个请求,一起等待相应,基本10s之内就能完成这个过程。

Python中多线程相关的模块包括:thread,threading,Queue。

thread:多线程的底层支持模块,一般不建议使用【本文暂不涉及】

threading:对thread进行了封装,将一些线程的操作对象化

Queue:实现了多生产者(Producer)、多消费者(Consumer)的队列

开始使用多线程

入门例子

python的threading库可以实现在单独的线程中执行任意的python可调用对象,我们通过创建Thread类的实例,然后提供其需要被单独线程执行的可调用对象,就完成目的了,看一个入门例子:

创建一个线程实例需要传递给它目标函数的引用,参数元组,然后调用start方法就会开始这个线程的运行。

通过Thread类可以有多种方法创建线程:

用一个函数作为参数实例化一个Thread类,多线程执行这个函数(上面例子所示)

用一个可调用类作为参数实例化一个Thread类,多线程执行这个“可调用类”(和第一个本质相同)

从Thread类派生一个子类,重写run方法(比较常规的用法)

多线程中的join

观察上面输出会发现“All done!”居然在最开始输出了,我们的本意是线程执行完之后才输出“All done!”,咋办呢?看下面一段代码:

这里介绍一下这个join,文档中有如下一句话:

"Wait until the thread terminates"

也就是说要等待这个线程执行完毕才开始后续操作,这样就实现了等待子线程完成再进行其他操作的目的。

该函数定义是def join(self, timeout=None): ...

也就是说还可以设置timeout参数,避免子线程出问题一直不结束的情况下父线程无限等待的问题

用一个可调用类作为参数实例化一个Thread类

先看下面代码:

如上,其实这里很好理解,主要注意的一个知识点是类的“call()”方法,这里的target is a callable object, 是一个可调用对象,MyThread(show, ('wing',))实例化了一个类,得到的对象就是这样一个可调用对象,和函数名对应,真正调用的时候就是执行了__call__()方法,这里的__call__()只是简单地执行初始化时传递过来的函数,类来实现相比于函数要灵活很多。

从Thread类派生一个子类,重写run方法(推荐的方法)

代码:

这里继承了threading模块的Thread类,重写了init和run方法,通过这种方式来实现多线程执行的效果。

多线程处理的返回值问题

上面的show函数只是简单的打印操作,但是如果需要多线程处理的函数如下:

这个时候需要记录函数执行的结果,在上面的实现中并不能达到这样的效果,这个时候我们可以稍微修改一下MyThread类,如下:

python线程同步机制

最后的结果是0,准确说多次执行发现结果是0,至于0是不是唯一结果,这里先不下结论,如果我们尝试把sleep(1)这一句注释放开,就会发现结果基本变成了-1

其实这里的sleep表示的只是对count操作之前的过程可能会耗时较长,这个时候count可能已经被改变了,而我们的本意是count大于0时才执行一次操作,本线程做这个处理的时候,不希望其他线程同时操作count的值。

再看下面一段代码:

如上,通过加锁实现了线程同步,这里的锁释放还可以用更优雅的方式实现,如下:

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180225A128FM00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券