Python线程使用和概念理解

布啦豆 7171

到目前为止,前面的章节文章都是单线程运行。就像一个人工作,必须一件事结束,再开始另一件事情,这就是所谓的单线程

多线程就是雇佣多个人,一起做同一件事或者将不同的事分给不同的人去做,可以大幅度的提交效率

先来看下多线程需要的库:Python内置的线程库threading

线程的运行,通过threading,初始化得到一个实例,然后给他一个可以执行的函数,让他执行就不用管了,就像你在电脑上把音乐软件打开,然后隐藏到后台,它还是会继续工作,然后你继续做你的事情是一样的意思。

能开一个线程,就能开多个线程.....

在代码中初始化一个线程,并给他函数让他执行,他跑到后台去执行了,然后代码可以继续往下工作,先上一段代码理解下:

import threading, time

def loop():
    print("loop start run")
    time.sleep(5)
    print("loop exit")

t = threading.Thread(target=loop, name="LoopThread")
t.start()
print("代码运行结束")

解释一下代码:

  • 首先导入两个库,一个是线程threading,另一个是time库【主要是sleep函数】
  • 然后在代码中,定义了loop函数,执行操作有打印loop start run,接着睡眠5秒钟,接着打印loop exit
  • 再是初始化一个线程,目标函数是loop,给线程赋一个名字LoopThread
  • 启动线程,然后不管了,脚本代码打印代码运行结束之后退出

先来看结果图:

python多线程

从结果图来看,整体运行了5秒,但是代码运行结束loop exit的前面,也就是说线程的运行情况和当前代码执行顺序无关,它只管运行它的。

就像是我有个任务——执行loop函数,我嫌函数无聊不想执行,我就找一个人来把我这个任务拿去执行,然后我做我的事。

理论上两个时间是重合的,时间会剪短,但是这里是看不出来的,因为代码执行的太快,时间和5秒相比毫无意义。

接下来定义两个,来测试一下时间问题:

import threading, time

def loop():
    print("loop start run")
    time.sleep(5)
    print("loop exit")

t1 = threading.Thread(target=loop, name="LoopThread-1")
t2 = threading.Thread(target=loop, name="LoopThread-2")
t1.start()
t2.start()
time.sleep(3)
print("代码运行结束")

这个示例是基于上一个示例的,现在创建两个线程,都在运行,理论上睡眠时间是5+5+3=13秒的,来看下具体执行情况:

thread多线程加时

还是短短的5.1秒,远小于13秒。

简单说下为什么:t1睡眠5秒的时间和t2睡眠5秒是重合的,还有代码睡眠3秒是在5秒的时间范围内的,所以最后的运行时间也就是程序开始,到程序全部结束的时间。

明白了线程的运行,然后继续了解下线程的其他知识点

知识点一:父线程和子线程

父线程和子线程是相对的。就拿刚才的示例来讲,代码执行是单线程,代码中创建了t1和t2,对于代码的单线程来讲,t1和t2是它的子线程,因为他们是被代码的单线程创建出来的。

知识点二:守护线程

守护线程和普通线程基本没什么区别,但是有一点特殊,即守护线程还没执行完,主线程退出,守护线程会强制退出;但是主线程执行结束,普通线程没结束,主线程会等待普通线程结束再退出

上一个示例代码和运行结果图:

import threading, time

def loop():
    print("loop start run")
    time.sleep(5)
    print("loop exit")
t = threading.Thread(target=loop, name="LoopThread")
t.setDaemon(True)
t.start()
print("代码运行结束")

Python守护线程

子线程还没结束,主线程已经结束了,强制退出,运行时间仅0.2秒。

对比本文第一个示例【非守护线程】,总执行时间有5.1秒呢

知识点三:线程和进程

线程:线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。一个线程是一个execution context(执行上下文),即一个cpu执行时所需要的一串指令。

进程:一个程序的执行实例就是一个进程。每一个进程提供执行程序所需的所有资源。(进程本质上是资源的集合)

一个进程有一个虚拟的地址空间、可执行的代码、操作系统的接口、安全的上下文(记录启动该进程的用户和权限等等)、唯一的进程ID、环境变量、优先级类、最小和最大的工作空间(内存空间),还要有至少一个线程。

知识点四:Python的线程是鸡肋?

用C、C++来写死循环,直接可以把全部核心跑满,4核就跑到400%,8核就跑到800%,但是Python是不行的。

因为Python的线程虽然是真正的线程,但解释器执行代码时,有一个GIL锁:Global Interpreter Lock,任何Python线程执行前,必须先获得GIL锁,然后,每执行100条字节码,解释器就自动释放GIL锁,让别的线程有机会执行。这个GIL全局锁实际上把所有线程的执行代码都给上了锁,所以,多线程在Python中只能交替执行,即使100个线程跑在100核CPU上,也只能用到1个核。

版权声明:允许转载,转载请注明出处 —— 《Python3教程》: Python线程使用和概念理解

Copyright @2016-2017 | 赣ICP备16003025号