Python线程基础

90 阅读5分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第13天,点击查看活动详情

线程理解

Python开发效率高,但是在执行效率上很让人诟病,所以在工作当中可能遇到这样的事情,突然有一个需求,比如:把800万用户访问信息进行存储操作,但是由于是日常运营测的任务,并且之前的项目主体上并没有这样的需求,所以需要临时进行开发,Python拥有对应数据库操作,字符串处理的模块,可以实现开发(当然,也有很多其他框架级的工具可以提供使用,比如,logstorage,但是在这里我们暂时来讨论一下Python),但是当我们运行的时候,反向执行的效率确实有点慢,不完全能或者完全不能达到我们的需求,那么这个时候,就需要考虑如何提高一下我们的开发效率,当然,编程过程当中,开发效率一直是一件让大家很重视的方法,也提供了从设计到编程到部署的多样化的优化策略,常见的提高代码执行效率的思路可以分为:

1、尽量减少程序等待的状态。

2、同时尽量多的运行程序。

那么技术的角度上可能出现的技术栈也有很多,比如:

1、多线程

2、多进程

3、协程

等等.......

这里举例的是代码层面的,框架层面的也有很多,就不在这里进行列举了,今天主要聊一聊Python的多线程。

开始之前先聊聊线程的概念:

1、我们通常把程序的一次执行看作是一个进程,进程拥有自己的内存空间,实际体验上就是当你打开桌面上的一个程序,这个时候,程序运行需要的空间会在计算机的内存当中创建出来,并且占有独立的一块空间,防止进程直接数据互相干扰。

2、线程是进程当中的一个小的分支,一个进程下面可以有多个线程,就好比大家去银行办理业务,这个时候银行可以看作为一个大的进程,线程是下面的一个一个运行的窗口。那么对照这个例子理解一个进程和线程之间的特性:

1)进程之间内存相互独立,所以进程并发容易理解,但是进程之间数据进行相互的通信就很难了。

2)线程共享父进程的内存空间,所以线程之间的通信是容易很多的。

3)线程和进程都存在生命周期,都有创建,运行,挂起的状态

Python线程开发

Python本身有多线程的功能,常用的模块是内置的threading模块,使用的方法很简单,可以理解为下面的几个步骤,在大家练习熟练之后可以进行灵活的使用。

完事儿怕但是(你是个好人,但是.......),同样在Python当中确实有多线程模块,但是并不是真正的多线程,因为多线程本身需要并行效果,而Python多线程并不能实现这样的效果,而是异步并发的效果,啥叫异步并发,就是将多个功能进行分解形成小的时间片进行运行,这样运行时间片,好处就是一个线程的时间片进入等待状态之后,可以运行其他线程的时间片,让计算机不至于进入完全的等待状态,这样来提高效率。

为啥会有这样的问题呢?因为Python在设计之处就是针对的单线程的环境设计的,Python当中有一个核心的概念叫做GIL(Global Interpreter Lock),全局解释器锁,他为了保证线程在运行的时候不被抢占,并且同时只有一个线程运行会对运行的线程加锁保护,这样其他线程就不可以运行了。随意Python的线程本质上是异步并发,并不能并行。

创建线程

threading模块创建线程的方法有两种:

1)调用threading.Thread

threading.Thread提供了target和args参数(当然其他参数在其他的并发部分会聊到),target参数指向线程运行的函数,args是运行函数的参数。从这里也能开出来,这个步骤实际上是把自己定义的函数放到线程上的一种操作。

2)重写threading.Thread

threading.Thread 是一个类,所以对于面向对象很熟悉的小伙伴可以直接定义类,然后继承threading.Thread,然后从写当中的run方法作为线程的功能,这种写法实际上就是创建了一个包含自己需要功能的线程。

线程运行

线程的运行其实很简单,直接调用线程的start方法就可以了。

线程挂起

线程是进程当中的一部分,并且是异步执行,如果不进行合理的管理可能出现,进程结束,线程还没有结束或者释放内存的场景,这个时候就需要进程等到线程结束后结束,多线程当中提供了使用守护线程或者join挂起的方法来做这件事:

守护线程,就是守护在进程内,在其他线程结束之前不让进程结束的进程(像守门的人),对线程对象设置setDaemon就可以了。

而join方法可以直接使用(我说Python多线程基础使用很简单,这会相信了吧)

惯用代码套路

from time import sleep
from threading import Thread

def say_hello(): #这里假如是一个功能函数
    sleep(1) #假装这个函数需要执行1秒
    print("hello world")

t_list = [] #这里创建的是一个存放线程的容器

for i in range(10):
    t = Thread(target=say_hello) #创建线程对象,加载say_hello函数
    t_list.append(t) #把创建好的线程放入t_list

for t in t_list:
    t.start() #运行线程

for t in t_list:
    t.join() #线程挂起,注意如果开始一个挂起一个,那么挂起的意义就不存在了。