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视频、源码、资料加群683380553免费获取

开始使用多线程

入门例子

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

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

 

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

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

  • 用一个函数作为参数实例化一个Thread类,多线程执行这个函数(上面例子所示)
  • 用一个可调用类作为参数实例化一个Thread类,多线程执行这个“可调用类”(和第一个本质相同)
  • 从Thread类派生一个子类,重写run方法(比较常规的用法)

多线程中的join

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

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

 

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

"Wait until the thread terminates"

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

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

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

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

先看下面代码:

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

 

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

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

代码:

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

 

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

多线程处理的返回值问题

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

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

 

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

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

 

python线程同步机制

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

 

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

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

再看下面一段代码:

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

 

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

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

 

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值