python-11-多线程模块threading
python使用多线程实例讲解
1 进程和线程
1.1 进程和线程的概念
进程(process)和线程(thread)是操作系统的基本概念。
进程是资源分配的最小单位,线程是CPU调度的最小单位。
线程是程序中一个单一的顺序控制流程,进程内一个相对独立的、可调度的执行单元,是系统独立调度和分派CPU的基本单位。
一、什么是进程
计算机程序只不过是磁盘中可执行的二进制(或其他类型)的数据,它们只有在被读取到内存中,被操作系统调用时才开始它们的生命周期。
进程是程序的一次执行。每个进程都有自己的地址空间、内存、数据栈及其他记录其运行轨迹的辅助数据。操作系统管理在其上运行所有的进程,并为这些进程公平分配时间、进程也可以通过fork和spawn操作来完成其他的任务。
不过进程有自己的内存空间,数据栈等,所以只能使用进程间通讯(Inter Process communication, IPC),而不能直接共享信息。
二、什么是线程
线程跟进程有些相似,不同的是:所有的线程运行在同一个进程中,共享相同的运行环境。
线程有开始,顺序执行和结束三部分。它有一个自己的指令指针,记录自己运行到什么地方。线程的运行可能被抢占(中断)或暂时的被挂起(睡眠),让其他线程运行,这叫做让步。
一个进程中的各个线程之间共享同一片数据空间,所以线程之间可以比进程之间更方便地共享数据以及相互通讯。线程一般都是并发执行的,正是由于这种并发和数据共享的机制使得多个任务的合作变成可能。
实际上,在单CPU的系统中,真正的并行是不可能的,每个线程会被安排成每次只运行一小会,然后就把CPU让出来,让其他的线程去运行。在进程的整个运行过程中,每个线程都只做自己的事,在需要的时候跟其他的线程共享运行的结果。
当然,这样的共享并不是完全没有危险的。如果多个线程共同访问同一片数据,则由于数据访问的顺序不同,有可能导致数据结果的不一致的问题,即竞态条件(race condition)。同样,大多数线程库都带有一些列的同步原语,来控制线程的执行和数据的访问。
另一个需要注意的是由于有的函数会在完成之前阻塞住,在没有特别为多线程做修改的情况下,这种“贪婪”的函数会让CPU的时间分配有所倾斜,导致各个线程分配到的运行时间可能不尽相同,不尽公平。
1.2 进程与线程的区别
(1)地址空间和其它资源(如打开文件):进程间相互独立,同一进程的各线程间共享。某进程内的线程在其它进程不可见。
(2)通信:进程间通信IPC,线程间可以直接读写进程数据段(如全局变量)来进行通信——需要进程同步和互斥手段的辅助,以保证数据的一致性。
(3)调度和切换:线程上下文切换比进程上下文切换要快得多。
(4)在多线程OS中,进程不是一个可执行的实体。
总结,进程和线程可以类比为火车和车厢。
(1)线程在进程下行进(单纯的车厢无法运行)。
(2)一个进程可以包含多个线程(一辆火车可以有多个车厢)。
(3)不同进程间数据很难共享(一辆火车上的乘客很难换到另外一辆火车,比如站点换乘)。
(4)同一进程下不同线程间数据很易共享(A车厢换到B车厢很容易)。
(5)进程要比线程消耗更多的计算机资源(采用多列火车相比多个车厢更耗资源)。
(6)进程间不会相互影响,一个线程挂掉将导致整个进程挂掉(一列火车不会影响到另外一列火车,但是如果一列火车上中间的一节车厢着火了,将影响到该趟火车的所有车厢)
(7)进程可以拓展到多机,进程最适合多核(不同火车可以开在多个轨道上,同一火车的车厢不能在行进的不同的轨道上)
(8)进程使用的内存地址可以上锁,即一个线程使用某些共享内存时,其他线程必须等它结束,才能使用这一块内存(比如火车上的洗手间【互斥锁mutex】)。
(9)进程使用的内存地址可以限定使用量(比如火车上的餐厅,最多只允许多少人进入,如果满了需要在门口等,等有人出来了才能进去【信号量semaphore】)。
1.3 多进程与多线程的概念与区别
(1)一个进程相当于一个要执行的程序,它会开启一个主线程,多线程会开启多个子线程;
(2)python设计之初没有多核CPU,所以它的多线程是一种并发操作(伪并行),它相当于把CPU的时间片分成一段一段很小的片段,然后分给各个线程交替进行,由于每个片段都很短,所以看上去像平行操作。
举个例子:现在有一个16核的CPU,一个要执行的数据读取任务A,我们将A分成多个进程并行操作,每个进程放到一个核上。但是如果将这个任务A用一个进程(开多个线程)完成的话,虽然一个核心同一时间处理一个线程,按理说16核可以同时处理16个线程(未考虑超线程技术),但由于python的缺陷,这里面的多线程依然是并发(伪并行)的,所以效率低。
1.4 Python的全局解释器锁GIL
Python代码的执行由Python虚拟机(也叫解释器主循环)来控制。Python在设置之初就考虑到要在解释器主循环中,同时只有一个线程在执行,就像单CPU的系统中运行多个进程那样,内存中可以存放多个程序,但任意时刻,只有一个程序在CPU中运行。
虽然Python解释器可以运行多个线程,但任意时刻,只有一个线程在解释器中运行。对Python虚拟机的访问由全局解释器锁(global interpreter lock,GIL)来控制,正是这个锁能保证同一时刻只有一个线程在运行。
在多线程环境中,Python虚拟机按以下方式执行:
(1) 设置GIL
(2) 切换到一个线程去运行
(3) 运行:a. 指定数量的字节码的指令,或者b. 线程主动让出控制(可以调用time.sleep(0))
(4) 把线程设置为睡眠状态
(5) 解锁GIL
(6) 再次重复以上所有步骤
在调用外部代码(如C/C++扩展函数)的时候,GIL将会被锁定,直到这个函数结束为止(由于这期间没有Python的字节码被运行,所以不会做线程切换)。编写扩展的程序员可以主动解锁GIL。不过Python开发人员则不用担心在这些情况下你的Python代码会被锁住。
2 python多线程实例
2.1 普通的单线程
# -*- coding: utf-8 -*-
from time import ctime,sleepdef music(name):for i in range(2):print("I was listening to music.----{}:{}".format(name, ctime()))sleep(1)def coding(code):for i in range(2):print("I was coding codes!----{}:{}".format(code, ctime()))sleep(5)if __name__ == '__main__':music("my love music")coding("python code")print("all over.----{}".format(ctime()))
我们先听了一首音乐,通过for循环来控制音乐的播放了两次,每首音乐播放需要1秒钟,sleep()来控制音乐播放的时长。接着我又敲了会代码,,每段代码需要5秒钟,通过for循环敲了两遍。
2.2 多线程
python提供了两个模块来实现多线程thread 和threading ,thread有一些缺点,在threading得到了弥补,我们直接学习threading 就可以了。继续对上面的例子进行改造,引入threadring来同时播放音乐和写代码:
2.2.1 设置守护线程(不等待)
在Python中,守护线程是指在程序运行时在后台运行的线程,当主线程结束时,守护线程也会随之结束。守护线程通常用于执行一些不需要阻塞主线程或长时间运行的任务。
# -*- coding: utf-8 -*-
from time import ctime,sleep
import threadingdef music(name):for i in range(2):print("I was listening to music.----{}:{}".format(name, ctime()))sleep(1)def coding(code):for i in range(2):print("I was coding codes!----{}:{}".format(code, ctime()))sleep(5)if __name__ == '__main__':threads = []t1 = threading.Thread(target=music, args=('my love music',))threads.append(t1)t2 = threading.Thread(target=coding, args=('python code',))threads.append(t2)for t in threads:# setDaemon(True)将线程声明为守护线程,必须在start()方法调用之前设置t.setDaemon(True)t.start()# 子线程启动后,主线程也继续执行下去print("all over.----{}".format(ctime()))
因为是守护线程,当主线程执行完最后一条语句print后,没有等待子线程,直接就退出了,同时子线程也一同结束。
从执行结果来看,子线程(muisc 、coding)和主线程(print all over)都是同一时间启动,但由于主线程执行完结束,所以导致子线程也终止。
若让主线程多等待8秒,则会正常输出。
if __name__ == '__main__':threads = []t1 = threading.Thread(target=music, args=('my love music',))threads.append(t1)t2 = threading.Thread(target=coding, args=('python code',))threads.append(t2)for t in threads:# setDaemon(True)将线程声明为守护线程,必须在start()方法调用之前设置t.setDaemon(True)t.start()# 子线程启动后,主线程也继续执行下去sleep(8)print("all over.----{}".format(ctime()))
2.2.2 不设置守护线程(等待)
if __name__ == '__main__':threads = []t1 = threading.Thread(target=music, args=('my love music',))threads.append(t1)t2 = threading.Thread(target=coding, args=('python code',))threads.append(t2)for t in threads:t.start()# 子线程启动后,主线程也继续执行下去print("all over.----{}".format(ctime()))
主线程执行结束以后,进程会等待子线程运行结束后,进程才会退出。
2.2.3 线程阻塞join方法
对上面的程序加了个join()方法,用于等待线程终止。join()的作用是,在子线程完成运行之前,这个子线程的父线程将一直被阻塞。
if __name__ == '__main__':threads = []t1 = threading.Thread(target=music, args=('my love music',))t2 = threading.Thread(target=coding, args=('python code',))threads.append(t2)threads.append(t1)for t in threads:t.setDaemon(True)t.start()t.join()# 子线程t1运行结束后,继续执行主线程print("all over.----{}".format(ctime()))
使用子线程t1阻塞,2秒后运行结束,线程t2还没运行结束。
相关文章:

python-11-多线程模块threading
python使用多线程实例讲解 1 进程和线程 1.1 进程和线程的概念 进程(process)和线程(thread)是操作系统的基本概念。 进程是资源分配的最小单位,线程是CPU调度的最小单位。 线程是程序中一个单一的顺序控制流程,进程内一个相对独立的、可调度的执行单…...

动态gif图片如何在线做?轻松实现图片在线生成gif
常见的jpg、png格式的静态图片想要变成gif格式的动态图片时,要怎么办呢?有没有什么简单实用的gif制作工具呢? 一、什么工具能够在线制作gif? GIF中文网作为一款专业的gif制作(https://www.gif.cn/)工具&a…...

浅谈联网汽车安全漏洞
“智能网联汽车存在内生共性问题,即软硬件的漏洞后门,基于此进行的网络攻击可以直接带来勒索、盗窃、大规模车辆恶意操控风险,还有数据泄露等网络安全事件。如果内生的漏洞后门问题不解决,系统自身难保,很难谈系统安…...

深入理解SeaTunnel:易用、高性能、支持实时流式和离线批处理的海量数据集成平台
深入理解SeaTunnel:易用、高性能、支持实时流式和离线批处理的海量数据集成平台 一、认识SeaTunnel二、SeaTunnel 系统架构、工作流程与特性三、SeaTunnel工作架构四、部署SeaTunnel1.安装Java2.下载SeaTunnel3.安装连接器 五、快速启动作业1.添加作业配置文件以定义…...

项目上线 | 兰精携手盖雅工场,数智驱动绿色转型
近年来,纺织纤维行业零碳行动如火如荼。作为低碳环保消费新时尚引领者,同时也是纤维领域隐形冠军,兰精在推进绿色发展的同时,也在不断向内探索企业数字化转型之道,以此反哺业务快速扩张。 数智转型,管理先…...

102-Linux_I/O复用方法之poll
文章目录 1.poll系统调用的作用2.poll的原型3.poll支持的事件类型4.poll实现TCP服务器(1)服务器端代码:(2)客户端代码:(3)运行结果截图: 1.poll系统调用的作用 poll 系统调用和 select 类似,也是在指定时间内轮询一定数量的文件描述符,以测试其中是否有…...

【VAR模型 | 时间序列】帮助文档:VAR模型的引入和Python实践(含源代码)
向量自回归 (VAR) 是一种随机过程模型,用于捕获多个时间序列之间的线性相互依赖性。 VAR 模型通过允许多个进化变量来概括单变量自回归模型(AR 模型)。 VAR 中的所有变量都以相同的方式进入模型:每个变量都有一个方程式ÿ…...

Spark任务提交流程
1. yarn-client Driver在任务提交的本地机器上运行,Driver启动后会和ResourceManager通讯,申请启动ApplicationMaster; 随后ResourceManager分配Container,在合适的NodeManager上启动ApplicationMaster,此时的ApplicationMaster的…...

python相对路径与绝对路径
9.1 Python 绝对路径与相对路径 - 知乎 (zhihu.com) 目录 1. 绝对路径 1.1 概念 1.2 用绝对路径打开文件 1.2 相对路径 1.3 python路径表示的斜杠问题 1. 绝对路径 1.1 概念 绝对路径 指完整的描述文件位置的路径。绝对路径就是文件或文件夹在硬盘上的完整路径。 在 Win…...

SPSS如何进行基本统计分析之案例实训?
文章目录 0.引言1.描述性分析2.频数分析3.探索分析4.列联表分析5.比率分析 0.引言 因科研等多场景需要进行数据统计分析,笔者对SPSS进行了学习,本文通过《SPSS统计分析从入门到精通》及其配套素材结合网上相关资料进行学习笔记总结,本文对基本…...

Python项目实战篇——常用验证码标注和识别(需求分析和实现思路)
前言:验证码识别和标注是现在网络安全中的一个重要任务,尤其是在一些电商平台和在线支付等场景中,验证码的安全性至关重要。本文将介绍如何使用Python实现常用的验证码标注和识别,以便为自己的项目提供参考。 一、需求分析 1、验证…...

MySQL基础(六)多表查询
多表查询,也称为关联查询,指两个或更多个表一起完成查询操作。 前提条件:这些一起查询的表之间是有关系的(一对一、一对多),它们之间一定是有关联字段,这个关联字段可能建立了外键,…...

零死角玩转stm32中级篇3-SPI总线
本篇博文目录: 一.基础知识1.什么是SPI2.SPI和IIC有什么不同3.SPI的优缺点4.SPI是怎么实现通信的5.SPI 数据传输的步骤6.SPI菊花链7.通过SPI实现数据的读和写 二.STM32F103C8T6芯片SPI协议案例代码 一.基础知识 1.什么是SPI SPI(Serial Peripheral Interface&#…...

顺序表功能实现(入手版详解)
🍉博客主页:阿博历练记 📖文章专栏:数据结构与算法 🚚代码仓库:阿博编程日记 🌹欢迎关注:欢迎友友们点赞收藏关注哦 文章目录 🍓前言✨顺序表🔍1.顺序表的整体…...

Java 中的线程是什么,如何创建和管理线程-下(十三)
书接上文 CompletableFuture CompletableFuture 是 Java 8 中新增的类,提供了更为强大的异步编程支持。它可以将多个异步任务组合成一个整体,并且可以处理异常情况。 例如,可以使用 CompletableFuture 来实现异步任务的串行执行࿱…...

为什么我的Windows 10 便签不支持更改字体?
Windows便签是一款常用的记录工具,可以帮助我们快速记录一些重要的信息。在使用Windows便签时,如果你想要更好地呈现你的信息,可以通过设置字体来达到这个效果。本文将介绍Windows便签字体设置的相关知识,希望对你有所帮助。 1、打…...

野火STM32电机系列(六)Cubemx配置ADC规则和注入通道
前文已经配置了GPIO、编码器 本节讲解CubeMXADC规则和注入通道 本文adc注入通道采用定时器触发,因此在上文定时器配置的基础上进行 常规信号(温度等)使用带DMA的常规通道连续采样 注入采样由定时器触发,采集电机三相电流&…...

预制菜,巨头们的新赛场
俗话说“民以食为天”,饮食对于大众的重要性自然是无需赘述。然而,随着生活节奏的加快,越来越多年轻人没有时间和精力去烹制菜肴,这也是外卖行业持续火热的重要原因之一。尽管如此,随着消费者健康意识的持续提升&#…...

英语语法第一章之英语语法综述
英语的任何句型基本都可以翻译成 什么怎么样 ,在这里什么就是我们常说的主语,而怎么样就是我们常说的谓语; 可能有些小伙伴会反问,不是主谓宾吗?别急等我慢慢讲解 在这里谓语也有很有多的不同的动作 可以独立完成的动作 句型&am…...

ChatGPT被淘汰了?Auto-GPT到底有多强
大家好,我是可夫小子,关注AIGC、读书和自媒体。解锁更多ChatGPT、AI绘画玩法。 说Auto-GPT淘汰了ChatGPT了,显然是营销文案里面的标题党。毕竟它还是基于ChatGPT的API,某种意义只是基于ChatGPT能力的应用。但最近,Auto…...

unity NGUI使用方法
基本用法 很多基本模块比如按钮、slider等都能从Prefab中直接拖拽到场景中实现,但都需要有一个Collider(Prefab已经自带) 因为不仅是UI,所有带有Collider的游戏物体都能接收到OnClick, OnPress这样的事件——前提是需…...

软件测试技术(五)软件测试流程
软件测试流程 软件测试流程如下: 测试计划测试设计测试执行 单元测试集成测试确认测试系统测试验收测试回归测试验证活动 测试计划 测试计划由测试负责人来编写,用于确定各个测试阶段的目标和策略。这个过程将输出测试计划,明确要完成的测…...

Redis缓存穿透和雪崩
Redis缓存穿透和雪崩 Redis缓存的使用,极大的提升了应用程序的性能和效率,特别是数据查询方面。但同时,它也带来了一些问题。其中,最要害的问题,就是数据的一致性问题,从严格意义上讲,这个问题…...

【C++】set和map的使用
对于STL容器来说,有很多相似的功能,所以这里主要将与之前不同的功能说清楚 文章目录 1.对于set与map的简单理解2. setinsert迭代器遍历countmultisetinsertfindcount 3. mapinsert与迭代器的使用统计水果次数 operator []operator[]的实现理解对整体的拆…...

大学生学java编程的就业前景怎么样?我来聊聊自己的见解
今天兴哥想跟大家分享一个话题,就是学java到底好不好找工作。因为我发现很多粉丝朋友,之前可能并不是从事IT行业的,然后想转行来做这一行,或者是有些大四即将面临毕业的老哥,可能大学没有好好学习吧,然后专…...

JavaScript全解析——canvas 入门(上)
●canvas 是 HTML5 新增的一个标签, 表示画布 ●canvas 也是 h5 的画布技术, 我们通过代码的方式在画布上描绘一个图像 canvas 标签 ●向进行 canvas 绘图, 首先我们先要了解到 canvas 标签 ●是 html5 推出的一个标签 <html> <head>... </head> <body&…...

vue 插槽的用法
Vue的插槽(Slot)是一种可以让父组件向子组件传递内容的机制。插槽可以让开发者将组件的结构和内容分离开来,从而实现更好的可维护性和复用性。 在Vue中,插槽通过 标签实现。具体用法如下: 单个插槽 在子组件中使用一…...

【C++复习2】C++编译器的工作原理
如果你是一名newbird的话,建议观看如下视频加深你的理解,再看如下内容: https://www.bilibili.com/video/BV1N24y1B7nQ?p7 The cherno会额外告诉你如何将目标文件转换成汇编代码,CPU执行指令的过程以及编译器如何通过删除冗余变…...

回调函数_回顾
函数指针和回调函数 函数指针是指向函数的指针变量。 通常我们说的指针变量是指向一个整型、字符型或数组等变量,而函数指针是指向函数。 函数指针可以像一般函数一样,用于调用函数、传递参数。 直接用指针表示函数,而不是*指针ÿ…...

今天面了个字节跳动拿35K出来的,真是砂纸擦屁股,给我露了一手啊
今年的金三银四已经结束,很多小伙伴收获不错,拿到了心仪的 offer。 各大论坛和社区里也看见不少小伙伴慷慨地分享了常见的面试题和八股文,为此咱这里也统一做一次大整理和大归类,这也算是划重点了。 俗话说得好,他山之…...