Python多线程的一些知识

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python多线程的一些知识相关的知识,希望对你有一定的参考价值。


Python多线程的一些知识

前言

了更好地体验多线程爬虫,本章先介绍下需要了解的知识点,以便后续的多线程爬虫文章有更好的理解与学习。

在接下来要讲的知识点中,感兴趣的读者们请先弄清楚进程和线程两者是什么?它们各自有着什么样的关系呢?读下廖雪峰老师简单介绍的例子,比喻非常生动清晰,故这里不多做讲解。

​https://www.liaoxuefeng.com/wiki/1016959663602400/1017627212385376​

看完后记住其中一个观念:进程是由若干线程组成的,一个进程至少有一个线程。(面试中常会问到的知识点)

多线程和计算机 cpu 之间的联系

经过上面的概念介绍,大家想两个问题,为什么在编写代码的过程中要使用多进程或者多线程?

世界上第一台计算机被美国国防部用来进行弹道计算。随着时间消逝,到了 20 世纪 70 年代以后,微处理机的出现,使电子计算机的应用越来越广泛。

同时,计算机本身的硬件也不断的发生了变化,比如早年的家用计算机只能存储 kb 单位的数据,而现在则可以存储 TB 以上的数据。又比如,计算机的核心组件 CPU 从原来的单核变为了多核。

Python多线程的一些知识_子线程

图片来源 百度

中央处理器(CPU,Central Processing Unit)是一块超大规模的集成电路,是一台计算机的运算核心(Core)和控制核心( Control Unit)。它的功能主要是解释计算机指令以及处理计算机软件中的数据。

百度

笔者现在用的这台 windows 电脑,如何查看它的 cpu 核心数呢?

按下 win 键(在 alt 左边) + R ,打开运行窗口,输入 cmd:

Python多线程的一些知识_多线程_02

输入 wmic,回车:

Python多线程的一些知识_多线程_03

再输入 cpu get *,回车:

Python多线程的一些知识_多线程_04

拖拽滚动条,看到下图:

Python多线程的一些知识_多线程_05

有 2 个核心,而笔者的 CPU 型号是:

Python多线程的一些知识_python_06

回到刚才提的问题中,不论是多线程还是多进程,最终的目的都是为了加快我们程序的运行速度,提高效率,节省时间。

假设有一家武器铺接到个订单,要打造 10 件武器。而打造武器需要铁匠,一个冶炼车间可以容纳 5 个铁匠进行冶炼。一个人打造一把武器用时 1 天。类比到计算机上, cpu 的核心数大家则可以想象成冶炼车间,有几个核心则有几个冶炼车间,线程数目可以想象成人数(老板与铁匠)。

武器铺老板(主线程)一共招收了 10 个铁匠小弟(子线程),但是早期的时候只有一个冶炼车间(cpu 核心数)。那么打造 10 件武器时,只能最多有 5 个人干活。第一天前 5 个铁匠干活,第二天后 5 个铁匠干活。这样加起来 10 把武器则需要 2 天才能完成。(单核心,多个线程在单个核心上间歇运行)

后来呢,皇城下的王子(订单主人)觉得武器店效率太慢!这样的效率不高,既然铁匠有 10 个人,那再造一间冶炼车间就好了呀!所以投资新建了一间冶炼车间。于是过些时日,武器店在接到打造 10 件武器时,只用了 1 天,10 个铁匠就打造了 10 把武器。(多核心,多个线程在多个的核心上高效运行)

通过这个看似恰当又不恰当的例子,其实想说的就是现在的 cpu 多核心时代,多线程/进程 可以尽量的充分利用每个核心,从而达到高效率执行任务。

Python 中的多线程

先来看看在 Python 中多线程如何使用?以上面打武器为例:

import threading
import time

def work():
thread_name = threading.current_thread().name
print(f铁匠小弟 thread_name 正在拼命打造武器... )
n = 0
while n < 5:
n = n + 1
print(f铁匠小弟 thread_name 抡大锤: n 次)
time.sleep(1)
print(f铁匠小弟 thread_name 打造武器完毕.)

def run():
thread_name = threading.current_thread().name # 获取当前线程名字
print(f武器铺老板 thread_name 吆喝开工...)
t1 = threading.Thread(target=work, name=1 号)
t1.start()
t1.join()
print(f武器铺老板 thread_name 吆喝结束...)

run()

结果如下:

Python多线程的一些知识_多线程_07

解释下代码,在 Python 中,官方提供了一个自带的 threading 包,使用它可以来手动创建线程。

首先调用 run 函数,在 run 函数里面,先获取主线程的名字。然后武器店老板吆喝小弟 1 号开工。通过 threading.Thread 创建一个新的子线程并将其赋值为 t1,而这个子线程的任务是什么呢?它的 target 参数指向要运行的函数,也就是 work。name参数是给子线程命名。

work 具体就是铁匠小弟抡大锤,打造武器。随后回到 run 函数,使用 t1.start() 和 t1.join(),直至最终结束。这里大家就要养成查看官方文档的好习惯啦。打开 python 中文官方文档,搜索 thread,打开后,可以看到相应的方法介绍。

start、join、name详细介绍都在下方。

Python多线程的一些知识_多线程_08

Python多线程的一些知识_Python_09

现在武器铺老板只召唤了 1 个小弟,那么在增加一个小弟呢?只需要改动下代码:

def run():
thread_name = threading.current_thread().name # 获取当前线程名字
print(f武器铺老板 thread_name 吆喝开工...)
t1 = threading.Thread(target=work, name=1 号)
t2 = threading.Thread(target=work, name=2 号) # 多的小弟
t1.start()
t2.start() # 多的小弟
t1.join()
t2.join() # 多的小弟
print(f武器铺老板 thread_name 吆喝结束...)

结果:

Python多线程的一些知识_多线程_10

Python多线程的一些知识_Python_11

Python多线程的一些知识_Python_12

笔者运行此程序一共三次,不难发现,三次输出的结果都是不一样的。怎么理解这个结果呢?

这就有点像抢冶炼车间的大喇叭,用来汇报自己的功劳,大家都喜欢抢功劳。假设现在铁匠小弟抡锤子一下,就需要喊一声:“我(比如是铁匠 1 号)抡大锤xx次了!” 由于每个冶炼车间的大喇叭只有一个,所以几号小弟先抢到,几号就能用喇叭喊出来!

在计算机中,每个线程都会去抢夺 cpu 的资源,谁抢到了,谁就可以“发声”!所以有时候是铁匠小弟 1 号先打印输出,有时候是铁匠小弟 2 号先打印输出。

以上就是在 Python 中如何编写一个简单的多线程例子。而对于该使用线程还是进程,在不同的场景则不尽相同。廖雪峰老师比较过二者,依然是给出文章地址:

​https://www.liaoxuefeng.com/wiki/1016959663602400/1017631469467456​

略微熟悉 Python 多线程的同学,应该都听说过“全局锁”的概念。正是这把"锁",让 Python(CPython 解释器下,有些 Python 解释器并没有) 在多线程的情况下有了效率低下之说。具体的就不给大家解释了,因为这把“锁”不是一言两语能说清楚的。。感兴趣的可以自行搜索。

结语

本章是为了给后续文章做一个铺垫。当然其中有些点可能比较难理解,如果有哪里不太懂或者笔者表达不对的地方,欢迎大家留言指出,共同交流!


文章首发公众号,欢迎关注:migezatan.(咪哥杂谈),不定期分享python文章哟!


以上是关于Python多线程的一些知识的主要内容,如果未能解决你的问题,请参考以下文章

python多线程知识-实用实例

python进程相关 - 多线程threading库

Python多线程多进程

Python多线程多进程

python基础知识~多线程

python基础知识~多线程