【多线程】

文章目录

  • 一、线程与进程的概念:
  • 二、多线程实现
  • 三、线程锁
  • 四、线程数量的设置

一、线程与进程的概念:

简单理解
假设总共有3个孩子需要喂饭,孩子每吃一口饭需要咀嚼消化一下。
多线程方案: 雇佣1个保姆,在喂A孩子吃饭,等到他开始咀嚼的时候,开始喂第二个孩子,等到第二个孩子开始咀嚼的时候,开始喂第三个孩子。
多进程方案: 雇佣3个保姆,3个保姆分别喂3个孩子。

线程与进程的概念

  • 进程是资源的分配和调度的独立单元。进程拥有完整的虚拟地址空间,当发生进程切换时,不同的进程拥有不同的虚拟地址空间。而同一进程的多个线程共享同一地址空间(不同进程之间的线程无法共享)
  • 线程是CPU调度的基本单元,一个进程包含若干线程(至少一个线程)。
  • 线程比进程小,基本上不拥有系统资源。线程的创建和销毁所需要的时间比进程小很多
  • 由于线程之间能够共享地址空间,因此,需要考虑同步和互斥操作
  • 一个线程的意外终止会影响整个进程的正常运行,但是一个进程的意外终止不会影响其他的进程的运行。因此,多进程程序安全性更高。

总之,多进程程序安全性高,进程切换开销大,效率低;多线程程序维护成本高,线程切换开销小,效率高。

并发
指在同一时间段内,有多个任务在交替执行。在多任务操作系统中,多个任务可以在同一时间共享CPU,因此表现出来的是并发执行的状态。这种情况下,多个任务的执行是交替进行的,每个任务都会分配到一定的时间片来执行,直到任务完成或者时间片用完。

并发可以提高系统的吞吐量和资源利用率,因为在同一时间段内,多个任务可以同时执行,从而提高CPU的利用率和系统的响应速度。但是,在并发执行中,由于CPU时间片的切换和任务间的上下文切换等开销,会降低系统的效率,增加系统的负担。此外,如果多个任务之间存在资源争用的情况,还需要采用同步机制来保证资源的正确性。

并行
是指在同一时间段内,有多个任务同时执行。在多处理器系统中,不同的处理器可以同时执行不同的任务,因此表现出来的是并行执行的状态。这种情况下,不同的处理器可以同时执行不同的任务,从而提高系统的性能和效率。

并行可以进一步提高系统的性能和吞吐量,因为不同的任务可以同时执行,而不需要等待其他任务的完成。这可以使得系统的处理能力得到充分的发挥,从而提高系统的响应速度和吞吐量。但是,在并行执行中,如果任务之间存在资源争用的情况,需要采用同步机制来保证资源的正确性和一致性。

并发与并行的区别
多线程在单核CPU上表现为并发,因为虽然多个线程同时执行,但在微观层面上仍然是交替执行的。然而,在多核CPU上,多线程可以并行执行,因为它们可以在不同的核心上同时执行。

多进程则不同,它们通常在多核或多CPU的计算机上并行执行。多进程是实现并行处理的有效方式,因为它们可以将任务分配到不同的CPU核心上,从而实现真正的并行处理。

二、多线程实现

线程的执行,是由CPU进行调度的,一个CPU在同一时刻只会执行一个线程,我们看上去的线程A 和 线程B并发执行。

为了让用户感觉这些任务正在同时进行,操作系统利用了时间片轮转的方式,CPU给每个任务都服务一定的时间,然后把当前任务的状态保存下来,在加载下一任务的状态后,继续服务下一任务。任务的状态保存及再加载,这段过程就叫做上下文切换。

Python中通过threading模块就可以很好地实现多线程,下面是一个简单的例子

import threading
import time# 在这里是每一个线程函数
def loop_func(i, sec):print("This is {} loop.".format(i))logging.warning(f'{i},{sec}')logging.info(f'{i},{sec}')time.sleep(sec)print("The {} loop finished.".format(i))def main():l = [10, 20, 15]  # 每个函数的循环时间,这里可以调整为不同线程的参数池ts = []for i in range(len(l)):# 实例化3个Thread对象,target指定调用的函数,args指定传给loop_func的参数thread = threading.Thread(target=loop_func, args=(i, l[i]))ts.append(thread)for i in range(len(l)):ts[i].start()  # 启动线程for i in range(len(l)):ts[i].join()  # 阻塞线程,使得主线程等到所有的子线程完成后再退出结束print("Main Thread Finished")if __name__ == "__main__":start_time = time.time()main()end_time = time.time()print("耗时:{:.2f}秒".format(end_time - start_time))

这里有4个重要的地方:

  1. 线程函数的编写,此处为loop_func
  2. 通过threading.Thread()方法,实例化线程
  3. 通过start()方法,启动线程
  4. 通过.join()方法,阻塞线程,使得主线程等到所有的子线程完成后再退出结束

需要注意的是,多线程的执行顺序是不确定的,线程的启动顺序不一定等于线程的执行顺序。

三、线程锁

线程锁(Tread Lock) 是一种同步机制,用于解决多线程访问共享资源可能出现的并发问题。在多线程环境下,多个线程对共享资源的访问可能导致数据不一致或其他不可预测的结果。线程锁通过对共享资源的访问进行控制,确保每一时刻只有一个线程能够访问共享资源,从而避免并发问题的产生。

线程锁的主要作用是保护共享资源,确保多个线程能够安全地访问共享资源。在多线程环境下,如果没有使用线程锁,可能会出现以下几种并发问题。

  1. 数据竞争(Data Race):多个线程同时读写共享资源,导致共享资源的值不确定或无法预测的结果。数据竞争是一种常见的线程安全问题,使用线程锁可以避免数据竞争的发生。在计算机操作系统中,所谓的I/O就是 输入(Input)和输出(Output),也可以理解为读(Read)和写(Write),针对不同的对象,I/O模式可以划分为磁盘IO模型和网络IO模型。通常磁盘IO是容易出现数据竞争的请求。同时在写入磁盘的
  2. 死锁(DeadLock)、
  3. 饿死(Starvation)等并发问题。
import threading# 共享资源
count = 0# 创建互斥锁
lock = threading.Lock()def increment():global count# 获取锁lock.acquire()try:# 修改共享资源count += 1finally:# 释放锁lock.release()# 创建多个线程并启动
threads = []
for _ in range(10):thread = threading.Thread(target=increment)threads.append(thread)thread.start()# 等待所有线程结束
for thread in threads:thread.join()# 打印结果
print("Count:", count)

四、线程数量的设置

业务中,存在大量的网络IO与磁盘IO,这些流程是十分耗时的。线程在IO处理的时候,CPU就空闲出来,利用率不高,但并不是线程设置越多越好

关于线程数量的设定,该博客讲解地很清晰。

最佳线程数目 = ((线程等待时间+线程CPU时间)/线程CPU时间 )* CPU数目

举例:服务器CPU核数为4核,一个任务线程cpu耗时为20ms,线程等待(网络IO、磁盘IO)耗时80ms,那最佳线程数目:( 80 + 20 )/20 * 4 = 20。也就是设置20个线程数最佳。

  1. CPU密集型:操作内存处理的业务,一般线程数设置为:CPU核数 + 1 或者 CPU核数*2。核数为4的话,一般设置 5 或 8
  2. IO密集型:文件操作,网络操作,数据库操作,一般线程设置为:cpu核数 / (1-0.9),核数为4的话,一般设置 40

https://blog.csdn.net/Rocky006/article/details/131655179
https://wenku.baidu.com/view/ab6ac3a2ac45b307e87101f69e3143323968f5d7.html
https://zhuanlan.zhihu.com/p/296796074

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/603020.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

人机之间的联系

人机之间的联系指的是人类和机器之间的交互和合作关系。人机联系的目的是通过利用机器的计算能力和人类的智能能力来实现更高效、更准确的工作和决策。 人机之间的看得见的链接,是指人与机器之间通过视觉、听觉等感官传递信息的方式,如人与电脑之间通过显…

生成式AI在自动化新时代中重塑RPA

生成式AI的兴起正在推动行业的深刻变革,其与RPA技术的结合,标志着自动化领域新时代的到来。这种创新性结合极大地提升了系统的适应性,同时也推动了高级自动化解决方案的发展,为下一代RPA的诞生奠定了坚实的基础。 核心RPA技术专注…

使用Java构建RESTfulWeb服务

构建RESTful Web服务是一种常见的Web开发方法,它提供了一种简单、可扩展和易于使用的方式来设计和实现Web API。Java作为一种强大而广泛使用的编程语言,提供了多种工具和框架来构建RESTful Web服务。在本文中,我将介绍如何使用Java构建RESTfu…

基础面试题整理2

1.抽象类与接口区别 语法: 抽象类用abstract定义;接口用interface定义抽象类被子类继承extends(不可用final修饰);接口被类实现implements抽象类的属性访问无限制,方法不可用private修饰;接口中的方法只能…

BRC20 技术分析

文章目录 什么是 BRC20 ?brc20 白皮书。重点基于链上数据解析获取交易详情返回值如何将 16 进制转换为 字符串没有节点,如何获取数据?见证隔离如何解析出 BRC20 数据?最后如何快速搭建节点BRC20 Indexer

[C#]使用sdcb.paddleocr部署v4版本ocr识别模型

【官方框架地址】 https://github.com/sdcb/PaddleSharp 【算法介绍】 PaddleOCR,全称为PaddlePaddle OCR,是PaddlePaddle深度学习平台下的一款强大的光学字符识别工具。它利用深度学习技术,实现了高精度的文字识别,可以帮助用户…

计数器的LED显示控制电路图

如图所示,图a中采用十进制七段存储-译码-驱动单元74143,此单元对所有段都有恒流输出。在电压为5V时每段电流约为15~22mA.七段译码器的BCD数据可以由脚17~20上取出。脚22用于进位,即当计数值到9后就为低电平,其余为高电平。利用这个信号可以控…

Eureka工作原理及代码实例

Eureka是Netflix开源的一个服务发现框架,它的作用是让分布式系统中的服务实例能够自动注册和发现。本篇博客将详细介绍Eureka的工作原理及其组件。 1、Eureka的基础组件 Eureka包含两个基本组件:Eureka Server和Eureka Client。Eureka Server为服务注册…

测试:Fuzz测试

简介 Fuzz测试(Fuzz Testing)是一种软件测试技术,其核心思想是向系统输入大量异常、随机生成的数据(称为“模糊数据”或“fuzz”),以此触发系统潜在的错误或漏洞,如崩溃、安全漏洞、性能问题等…

Python:isalpha() 和 isalnum() 区别

isalpha() 和 isalnum() 是 Python 中的字符串方法,用于判断字符串是否仅包含特定类型的字符。下面我会逐个介绍这两个函数的语法结构、参数含义、使用举例和适用场景,并解释它们之间的区别。 一、isalpha() 语法结构:string.isalpha() 参数…

Matlab:遗传算法,模拟退火算法练习题

1、遗传算法 (1)遗传算法是一种基于自然选择原理和自然遗传机 制的搜索(寻优)算法,它是模拟自然界中的生命进化机制,在人工系统中实现特定目 标的优化。遗传算法的实质是通过群体搜索技术,根据…

神经网络中的重要概念

神经网络是一种模拟生物神经网络结构和功能的计算模型,由许多节点(或称为神经元)和它们之间的连接构成。以下是一些神经网络中的重要概念,并对它们进行细致的讲解: 神经元(Neuron):神…

捕捉“五彩斑斓的黑”:锗基短波红外相机的多种成像应用

红外处于人眼可观察范围以外,为我们了解未知领域提供了新的途径。红外又可以根据波段范围,分为短波红外、中波红外与长波红外。较短的SWIR波长——大约900nm-1700nm——与可见光范围内的光子表现相似。虽然在SWIR中目标的光谱含量不同,但所产…

Debezium发布历史51

原文地址: https://debezium.io/blog/2019/03/14/debezium-meets-quarkus/ 欢迎关注留言,我是收集整理小能手,工具翻译,仅供参考,笔芯笔芯. Debezium 遇见 Quarkus 三月 14, 2019 作者: Jiri Pechanec qu…

瓢虫目标检测数据集VOC格式400张

瓢虫,一种小巧玲珑、色彩鲜艳的昆虫,因其独特的形态和生态习性而受到广泛欢迎。 瓢虫的体型小巧,一般为圆球形,体色鲜艳,有红、黄、黑等多种颜色。它们通常有一个坚硬的外壳,可以保护自己不受天敌的侵害。…

Spark回归分析与特征工程

回归分析是统计学和机器学习中的一个重要分支,用于建立因变量与自变量之间的关系模型。在大数据领域,Apache Spark为回归分析提供了强大的工具和库,以处理大规模数据集。本文将深入探讨如何使用Spark进行回归分析以及如何进行特征工程&#x…

AtomicReference自旋加CAS保证对象引用原子性

AtomicReference类提供了对象引用的非阻塞原子性读写操作,并且提供了其他一些高级的用法,对象的引用其实是一个4字节的数字,代表着在JVM堆内存中的引用地址,对一个4字节数字的读取操作和写入操作本身就是原子性的 package Atomic…

【微服务合集】

文章目录 MyBatisPlusMyBatisPlus 注解WrapperMybatisPlus批量插入(saveBatch)MyBatisPlus 分页插件 DockerDockerfileDocker网络Docker部署项目 黑马微服务文档尚硅谷SpringBoot2尚硅谷SpringBoot3 MyBatisPlus MyBatisPlus 注解 TableName TableId TableField MyBatisPlu…

冬天夺去的清爽,可爱,春天都会还给你

这款外套上身可太时尚好看了 春天日常穿着或者出行游玩 应对早晚温差,兼具时尚和温度两不误 干净率性闲适的洒脱范整件衣服干净不失细节 下摆有橡筋收紧更加保暖了工艺方面也毫不逊色,防水拉链 四合扣、猪鼻扣一应俱全简直就是一件实用与时尚并存的…

Embedded-Project项目介绍

Embedded-Project项目介绍 Server后端项目后端启动连接数据库启动时可能遇到的问题架构介绍 web前端项目前端启动启动时可能遇到的问题架构介绍 前后端分离开发流程 项目地址: https://github.com/Catxiaobai/Embedded-Project Server后端项目 系统后端项目&#…