Python线程

什么是并行性(parallelism)

早期的机器在 CPU 中只有一个内核(core),所有处理都在这个内核中进行。
为什么内核的数量很重要——这是因为它说明了机器处理多种事情的能力。 如果您有 16 个内核,那么您可以同时执行 16 种不同的操作
假设您要执行 16 种不同的加法运算,并假设每个运算需要 1 秒。 在单核机中,这些操作必须一个一个地执行,也就是说16个加法运算在16秒内完成。 现在在一台 16 核的机器上,你可以将 16 个加法操作同时部署到每个核上,并在 1 秒内完成工作。 这称为并行性

线程处理(threading)

线程(thread)是一组需要执行的操作。 一个线程将部署在 CPU 中的一个内核中。
注意: 1 个线程只能部署在 1 个内核中,不能转移/交换。
让我们将两个线程部署到一个内核。
注意 :一个内核一次只能做一件事。
在这里插入图片描述

现在我们可以按我们想要的方式处理这两个线程。
首先,我们可以处理第一个线程的一半。
在这里插入图片描述
现在可以处理下一个线程的一半。
在这里插入图片描述
其余一半的线程可以以类似的方式处理。
在这里插入图片描述
这就是线程——这是我们如何在同一个 CPU 内核上运行不同的东西。 线程处理(threading)是关于我们如何处理内核中的线程

注意:线程不涉及在多个内核上运行。 它是关于如何在同一个内核中对一组程序(线程)进行排序。

为什么我们需要线程处理?

有时,线程可能会挂起(hanging),这意味着它应该在那个时间点处于空闲(idle)状态。 最好的例子是 time.sleep() 函数,它什么都不做,只是等待给定的时间。 当一个线程空闲/挂起时,我们可以继续处理另一个线程直到前一个线程变为活动状态当一个线程正在等待时,您可以同时处理另一个线程。
这就是我们所说的并发计算(concurrent computing)。

一个小例子

让我们用一个小例子来解释线程。查看下面的代码片段。

#Part One of the code
import time
print(1)
time.sleep(10)
print('Done sleeping)
print(2)

#Part Two of the code
print(3)

输出如下所示:

1
Done sleeping
2
3

现在让我们假设您将代码作为两个线程执行。 第一部分作为一个线程,第二部分作为一个线程。 (注意——默认情况下,Python 代码没有配置线程——我们需要导入threading 库来做到这一点。)

首先导入库 threading,然后打印‘1’。 现在线程进入睡眠状态。 这就是线程发挥作用的地方。

在这里插入图片描述
内核现在切换到另一个线程。

在这里插入图片描述
现在打印了“3”。因为所有进程都是在线程2中完成的,所以内核现在切换回线程1(它仍然处于睡眠状态)。
在这里插入图片描述
现在,在睡眠时间之后,’ 2 '被打印出来。
所以输出是

1
3
Done sleeping
2

实际例子

I/O进程(processes)受益于线程。
假设你正在Netflix上看《肖申克的救赎》。当你看着Andy Dufresne在监狱里受苦时,会发生两件事:一,应用程序从服务器获取数据;二,获取的数据会像电影一样显示在你的屏幕上。
在这里插入图片描述
想象一下如果没有线程处理会是什么情况。你需要偶尔等待视频被下载,观看被获取的片段,等待下一个片段被下载,等等。
由于有了线程处理,我们可以将两个进程分成不同的线程。当一个线程获取数据时(也就是说,它处于挂起/休眠模式),另一个线程可以向您展示Morgan Freeman的表演。
它对作为数据科学家的您也非常有用。例如,当您从多个网页抓取数据时,您可以简单地将它们部署在多个线程中,使其更快。即使将数据推送到服务器,也可以在多个线程中进行,这样当一个线程空闲时,就可以触发其他线程。

更细致的例子

如前所述,默认情况下,Python代码不提供线程处理——我们需要导入 threading 库来实现这一点。

import threading
import time

def sleepy_man(secs):
    print('Starting to sleep inside')
    time.sleep(secs)
    print('Woke up inside')

x = threading.Thread(target = sleepy_man, args = (1,))
x.start()
print(threading.activeCount())
time.sleep(1.2)
print('Done')

代码输出如下:

Starting to sleep inside
2
Woke up inside
Done

首先,让我一步一步解释代码。 然后我们将分析输出。

  • 首先导入 threading 和 time 库。 threading 是允许我们创建线程的库,time 是包含函数 sleep 的库。
  • 函数 sleepy_man 接受一个参数——秒。 它首先打印“Starting to sleep inside”。 然后它会休眠几秒钟,然后打印“Woke up inside”。
  • 这是我们开始创建线程的部分。 我们需要通过调用类threading.Thread来定义。 我们需要传递两个参数——target 是需要线程化的函数块,args 是需要传递给函数的参数。 返回一个线程对象,该对象现在存储在 x 中。
x = threading.Thread(target = sleepy_man, args = (1,))
  • 现在定义线程类后,我们需要调用函数 start() 来启动线程
x.start()
  • 注意:现在我们有了两个线程。该程序的一个默认线程和一个我们定义的新线程因此活动线程数为 2
  • 因此,该语句应该输出’ 2 '。
print(threading.activeCount())

现在让我们来看看控制的流程。一旦调用 start() 方法,它就会触发 sleepy_man(),并在单独的线程中运行
主程序也将作为另一个线程并行运行。流程如下图所示。
在这里插入图片描述现在让我们增加函数中程序休眠的时间

import threading
import time

def sleepy_man(secs):
    print('Starting to sleep inside')
    time.sleep(secs)
    print('Woke up inside')

x = threading.Thread(target = sleepy_man, args = (4,))
x.start()
print(threading.activeCount())
time.sleep(1.2)
print('Done')

输出如下:

Starting to sleep inside
2
Done
Woke up inside

流程如下图所示
在这里插入图片描述
现在让我们运行一个触发多个线程的 for 循环。

import threading
import time

def sleepy_man(secs):
    print('Starting to sleep inside - Iteration {}'.format(5-secs))
    time.sleep(secs)
    print('Woke up inside - Iteration {}'.format(5-secs))

for i in range(3):
    x = threading.Thread(target = sleepy_man, args = (5-i,))
    x.start()

print('Active threads- ', threading.activeCount())

在每次迭代中,我们触发一个线程。注意,我们分别在第1次、第2次和第3次迭代时传递参数5、4、3。因此sleepy_man()的睡眠时间分别为5秒、4秒和3秒。
输出如下:

Starting to sleep inside - Iteration 0
Starting to sleep inside - Iteration 1
Starting to sleep inside - Iteration 2
Active threads-  4
Woke up inside - Iteration 2
Woke up inside - Iteration 1
Woke up inside - Iteration 0

因此,我们已经看到了如何定义和触发多个线程,确保了更好的处理方式,这对于繁重的I/O操作非常重要。

参考

本文主要参考Beginners Guide to Threading in Python

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

培之

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值