当前位置: 首页 > news >正文

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

相关文章:

  • 实用小代码之内存泄漏检测(二)
  • Python多进程 multiprocessing
  • 80后心灵独白
  • Python GIL
  • 风波已过去六年
  • 针对 RGB 图像,用 cv2、matplotlib、PyTorch库处理需要变换
  • 十招解决Linux磁盘空间分区不合理
  • cv2.resize 参数先宽度后高度
  • tensor[None]
  • 五种MySQL数据库高可用性方案分析和比较
  • OMP: Error #15: Initializing libiomp5md.dll, but found libiomp5md.dll already initialized.
  • 《荒漠甘泉》4月18日
  • GAMES 101 笔记
  • 真想小宝啊
  • google比百度搜索能力强
  • 【Amaple教程】5. 插件
  • 【笔记】你不知道的JS读书笔记——Promise
  • JavaScript实现分页效果
  • Map集合、散列表、红黑树介绍
  • Nacos系列:Nacos的Java SDK使用
  • node-sass 安装卡在 node scripts/install.js 解决办法
  • Spring Cloud中负载均衡器概览
  • vue 个人积累(使用工具,组件)
  • Vue学习第二天
  • 前端面试题总结
  • 浅谈JavaScript的面向对象和它的封装、继承、多态
  • 实现菜单下拉伸展折叠效果demo
  • 我有几个粽子,和一个故事
  • 小试R空间处理新库sf
  • 一道闭包题引发的思考
  • AI又要和人类“对打”,Deepmind宣布《星战Ⅱ》即将开始 ...
  • 从如何停掉 Promise 链说起
  • 组复制官方翻译九、Group Replication Technical Details
  • ​ubuntu下安装kvm虚拟机
  • ###项目技术发展史
  • (17)Hive ——MR任务的map与reduce个数由什么决定?
  • (2)MFC+openGL单文档框架glFrame
  • (C#)一个最简单的链表类
  • (java版)排序算法----【冒泡,选择,插入,希尔,快速排序,归并排序,基数排序】超详细~~
  • (ZT)北大教授朱青生给学生的一封信:大学,更是一个科学的保证
  • (二) Windows 下 Sublime Text 3 安装离线插件 Anaconda
  • (六)vue-router+UI组件库
  • (每日持续更新)信息系统项目管理(第四版)(高级项目管理)考试重点整理 第13章 项目资源管理(七)
  • (七)理解angular中的module和injector,即依赖注入
  • (三分钟)速览传统边缘检测算子
  • (转)Android学习笔记 --- android任务栈和启动模式
  • .net core webapi 部署iis_一键部署VS插件:让.NET开发者更幸福
  • .net core控制台应用程序初识
  • .NET Framework 3.5中序列化成JSON数据及JSON数据的反序列化,以及jQuery的调用JSON
  • .net wcf memory gates checking failed
  • .NET 同步与异步 之 原子操作和自旋锁(Interlocked、SpinLock)(九)
  • .net项目IIS、VS 附加进程调试
  • /etc/shadow字段详解
  • @Query中countQuery的介绍
  • [20161101]rman备份与数据文件变化7.txt