概叙
相信作为一个IT工程师,搞懂单核/多核、线程/进程、串行/并行、并行/并发、同步/异步、阻塞/非阻塞等概念、及其背后的技术是必要的。
科普文:软件架构之Linux系列【操作系统基本概念】-CSDN博客
科普文:软件架构之Linux系列【操作系统:处理机调度Schedule/Dispatcher】-CSDN博客
科普文:软件架构之Linux系列【CPU调度策略】-CSDN博客
科普文:软件架构之Linux系列【Linux进程调度:探索内核核心机制】-CSDN博客
科普文:软件架构Linux系列之【CPU、内存、操作系统之间的联系】-CSDN博客
通过前面梳理的文章,我们对计算机原理的基础:CPU、操作系统、调度都有一个基本的认识,再去理解单核/多核、线程/进程、串行/并行、并行/并发、同步/异步、阻塞/非阻塞等概念就会很容易。
在单核/多核、线程/进程、串行/并行、并行/并发、同步/异步、阻塞/非阻塞等这些概念里面,其实只需要先理解并行/并发,这个是本质,不然为啥叫并发编程/系统如何支持高并发/服务器如何抗住高并发,其他的都是围绕并行/并发的不同解决方案。
如果本文有不严谨或者疏忽的地方,欢迎批评指正。
串行/并行/并发
并行:指两个或多个事件在同一时刻发生(同时发生)。
并发:指两个或多个事件在同一个时间段内发生。
概念
-
并发(Concurrency):
-
-
-
指在同一时间段内处理多个任务或事件。并发并不一定意味着这些任务是同时进行的,而是它们在时间上有重叠。
- 并发可以通过多线程、事件驱动编程或协作式多任务来实现。在并发模型中,多个任务共享同一资源(如 CPU),并通过时间片轮转来切换,多个任务在一段时间内交替执行,虽然并不一定是同时进行的。
- 并发的主要目的是提高系统的吞吐量和响应性,以更好地处理多个任务。
-
-
并行(Parallelism):
-
-
-
指同时执行多个任务或操作。并行意味着在物理上真正同时进行任务,通常依赖于多个处理器核心或多个计算设备。
- 并行计算需要硬件支持(如多核 CPU),能够真正同时处理多个计算任务。它表示多个任务可以在不同的处理器、核心或计算资源上同时执行。
- 并行的主要目的是通过同时执行多个任务来加速处理速度,提高系统的计算能力和效率。
-
-
串行(Serial/Sequential):
-
-
- 串行(serial)与并行(parallel)相对应,是指的我们从事某项工作时一个步骤一个步骤的去实施。
- 指同时执行有且仅有1个任务或操作。串行意味着在物理上真正同时进行任务只能有一个,其他任务或者操作都要等待其结束后,再逐一运行。
- 串行方式在处理单一任务时效率较高,但是在处理多个任务时,如果任务之间存在依赖关系,就需要等待前一个任务完成,这就会大大降低效率。
区别
并行是指多个任务在同一时刻在多个处理器或者多核处理器上同时执行。并发是指多个任务在同一时间间隔内交替执行,但在任意时刻只有一个任务在执行。
并行需要硬件上的支持,而并发需要软件上的支持。并行是物理上的同时发生,而并发是逻辑上的同时发生。
实际应用场景
- 并发:适用于单核或多核处理器系统。在单核处理器上,并发通过时间分片来实现多任务处理;在多核处理器上,并发可以真正地同时执行多个任务。
- 并发应用场景包括多种场景,每种场景都有其特定的挑战和需求。以下是一些常见的并发应用场景及其复杂性。
- 例如,Web服务器处理多个请求时,虽然单个请求是串行的,但多个请求可以并发处理。
- 电商平台:在双十一、黑色星期五等大促销活动期间,电商平台会迎来大量用户同时下单、支付和浏览商品。这要求系统能够处理大量的订单生成和支付请求,保证订单的唯一性和准确性,实时更新库存以避免超卖或库存不足,并高效管理用户会话和负载均衡。
- 社交网络:社交网络平台上,用户频繁发布、评论、点赞和分享内容。这需要实时推送消息通知给大量用户,保证消息的及时性和准确性,高效缓存和数据库读取动态内容,并处理高并发的用户互动请求,保障数据一致性和并发控制。
- 在线直播:在线直播平台在大型直播活动期间会迎来大量观众同时观看、评论和打赏。这要求系统能够高效处理视频流,保证视频播放的流畅性,实时显示观众的评论和打赏,并高效负载均衡和CDN分发。
- 在线游戏:大型多人在线游戏需要支持成千上万玩家同时在线互动。这需要实时同步游戏状态,保证游戏的公平性和一致性,高效网络传输和延迟控制,以及服务器分区以避免单点过载。
- 金融交易系统:股票交易、外汇交易等金融系统在交易高峰期会有大量交易请求。这要求系统能够高效撮合交易,保证交易数据的实时性和一致性,防范各种攻击和风险,确保系统的安全性。
- 搜索引擎:搜索引擎需要处理大量的搜索请求并返回相关结果。这需要高效的查询优化算法,快速响应搜索请求,高效处理和存储频繁更新的索引数据,以及分布式存储和管理大量数据。
- 物联网(IoT)平台:大量物联网设备同时上传数据或接受控制命令。这要求系统能够高效处理和存储设备数据,保证数据的实时性和一致性,以及高效的设备管理和控制。
- 这些场景共同展示了并发应用在不同领域的广泛应用和挑战,每种场景都需要特定的技术解决方案来应对高并发带来的性能和稳定性问题。
- 并行:适用于多核处理器或分布式系统。在多核处理器上,每个核心可以同时执行一个任务;在分布式系统中,多个节点可以同时处理不同的任务。
- 例如,大规模科学计算、大数据处理等场景中,并行计算可以显著提高效率。
-
多核CPU执行任务,因为多核CPU可以同时处理多个任务,可以采用并行方式;
-
需要加速任务的执行速度,如图像处理、视频编码、数据挖掘等计算密集型任务;
-
任务之间不存在依赖关系,可以独立执行,如多个用户同时访问网站的请求处理。
-
- 例如,大规模科学计算、大数据处理等场景中,并行计算可以显著提高效率。
- 串行:适用于单核处理器上的简单任务处理。由于只有一个处理器,所有任务必须按顺序执行。
-
单核CPU执行任务,因为单核CPU只能处理一个任务,只能采用串行方式;(单核)
-
需要保证任务的顺序性,即必须先完成前一个任务才能进行下一个任务的场景,如编译代码时需要按照文件依赖关系依次编译;(有序性/阻塞)
-
任务之间存在依赖关系,后一个任务需要使用前一个任务的输出结果作为输入,如数据处理任务。(有序性/阻塞)
-
并发和高并发带来的问题
并发和高并发带来的问题主要包括以下几个方面:
-
系统性能问题:高并发会增加系统的负载,可能导致系统响应变慢、服务崩溃或停止响应。这会导致用户体验下降,甚至系统无法正常工作。
-
数据不一致:在高并发场景下,多个用户同时对同一数据进行读写操作,可能导致数据的不一致性。这会影响系统的稳定性和数据的准确性。
-
安全问题:高并发环境容易引起安全问题,如DDOS攻击、SQL注入、XSS攻击和CSRF攻击等。这些攻击可以利用系统负载过高的漏洞,对系统进行恶意攻击,导致信息泄露或系统崩溃。
-
缓存穿透:在高并发场景下,如果缓存失效,大量请求直接落到数据库上,可能导致数据库压力过大,甚至宕机。这种情况在恶意攻击下尤为严重。
-
队列问题:高并发环境下,请求容易出现排队等待的情况。如果队列管理不当,可能导致队列拥堵,请求失败或超时。
-
资源浪费:高并发请求可能会导致系统资源浪费,例如内存或CPU资源被占用过多,导致其他请求无法正常运行。
解决这些问题的方法包括:
-
使用缓存:通过缓存技术减少对数据库的直接访问,减轻数据库的压力。合理配置缓存策略,避免缓存穿透和击穿。
-
负载均衡:通过负载均衡器分发请求,合理分配服务器负载,避免单点故障和资源浪费。可以使用Nginx等工具实现负载均衡。
-
数据库优化:采用数据库集群、读写分离等技术,提高数据库的处理能力和可用性。使用主从同步和主备切换机制,确保数据库的高可用性。
-
系统架构优化:通过业务分层、系统分级、服务分布等方式,将系统拆分成更小的模块,分别优化每个模块的性能。采用模块化设计和任务并行化策略,提高系统的整体处理能力。
-
安全加固:加强系统的安全防护,定期进行漏洞扫描和修复,采用安全算法和技术,防止恶意攻击。
通过这些方法,可以有效应对高并发带来的各种问题,提升系统的性能和稳定性。
高并发系统的瓶颈
高并发系统的瓶颈主要包括以下几个方面:
-
CPU资源:在高并发情况下,CPU的负载会显著增加,导致处理速度变慢。CPU资源是并发访问的临界资源之一,多个进程或线程同时访问时,可能会导致性能瓶颈。
-
内存资源:内存资源的消耗在高并发环境下也会成为瓶颈。频繁的内存访问和分配会导致内存使用量激增,尤其是在多线程环境中,内存管理不当会导致性能下降。
-
网络资源:网络带宽和延迟在高并发情况下也会成为瓶颈。大量的数据传输和请求响应需要消耗大量的网络资源,导致响应时间延长。
-
硬盘资源:读写操作频繁的硬盘在高并发环境下可能会成为瓶颈,尤其是当硬盘I/O成为瓶颈时,会影响整个系统的性能。
-
数据库:数据库的查询和处理速度在高并发环境下可能会变慢,尤其是在进行大量读写操作时,数据库的性能瓶颈会显著影响整个系统的响应速度。
解决高并发系统瓶颈的方法包括:
-
硬件升级:通过提升硬件性能,如增加内存、使用多核CPU、采用固态硬盘等,可以有效提升系统的处理能力。
-
负载均衡:通过硬件负载均衡设备(如F5)或软件负载均衡(如LVS、Nginx)来分散负载,提升系统的并发处理能力。
-
缓存技术:使用缓存来减少对数据库的访问,例如使用Redis、Memcached等分布式缓存技术,可以提高系统的响应速度和并发处理能力。
-
异步处理:通过异步调用和消息队列(如RocketMQ)来减少同步调用带来的阻塞,提高系统的整体处理效率。
-
数据库优化:通过读写分离、分库分表、合理使用索引等技术手段优化数据库性能,减少数据库成为瓶颈的可能性。
-
系统架构优化:采用微服务架构、使用Docker容器技术等手段,提高系统的可扩展性和可用性,降低单点故障的风险。
如何设计能抗住高并发的系统
-
采用分布式+微服务+集群的架构:将系统拆分成多个独立的模块,每个模块可以独立部署和扩展。每个模块可以部署多个实例,通过负载均衡将流量合理地分发到多个服务器上,从而减少单个服务器的压力,避免单点过载导致服务中断。
-
负载均衡:通过负载均衡技术,将网络流量分配到多个服务器上,确保任何一台服务器不会被过载。常见的负载均衡策略包括轮询法、加权轮询法和哈希法等。例如,Nginx 是一个流行的 Web 服务器和反向代理服务器,可以轻松实现负载均衡。
-
自动扩展机制:在流量高峰期自动增加新的服务器实例,流量低谷时期自动减少实例,从而支持大规模并发访问,且节省成本。这种机制可以根据提前预知的大流量情况,提前配置性能更好的服务器。
-
缓存技术:使用缓存技术来缓存热点数据,减少服务对数据库的直接访问。常见的缓存策略包括使用分布式缓存系统,如Redis,来存储频繁访问的数据,提高访问速度。
-
限流策略:通过令牌桶算法或漏桶算法来控制系统访问量,防止系统因过载而崩溃。常见的限流策略包括令牌桶算法和漏桶算法,其中令牌桶算法在灵活度上比漏桶算法更好,并且在处理偶发的大流量时效果更好。
-
数据库优化:为了提升数据库性能,可以采用分库分表+读写分离的策略来降低单数据库单表的压力。建立合理的索引,提升数据库查询效率。同时,使用缓存技术来减少对数据库的访问。
-
池化技术:预先分配资源到对象池中,之后的业务使用资源从对象池中获取,使用完后放回到对象池中。这样可以减少资源分配和释放过程中的系统消耗,提升系统性能3。
-
系统监控和预警:使用监控工具实时监控系统的健康状态,如服务器的性能指标、网络流量、数据库响应时间、CPU等。设置告警线,当指标达到某个值时,系统便发出预警,便于技术人员定位和解决问题。
通过以上方法,系统可以在高并发环境下保持高性能和高可用性,确保服务的稳定运行。
高并发系统优化思路
高并发系统的优化需要从多个方面入手,综合考虑系统架构、数据库、缓存、网络等因素。
Java web应用性能分析之服务端慢和优化概叙_cpu飙高java-CSDN博客
以下是一些常见的高并发优化思路:
1. 系统架构优化
分布式架构:将单体应用拆分为多个微服务,每个微服务独立部署和扩展,减少单个服务的负载。
水平扩展:增加服务器节点,通过负载均衡将请求分发到多个服务器,提升系统的处理能力。
异步处理:采用异步编程模型和消息队列,减少请求的阻塞时间,提高系统的响应速度。
科普文:分布式架构中的三高:高并发、高性能、高可用_分布式高并发-CSDN博客
科普文:分布式系统的架构设计模式_分布式系统架构-CSDN博客
科普文:微服务之微服务技术栈分析_微服务开发技术栈-CSDN博客
科普文:微服务之微服务框架Spring Cloud Alibaba组件简介-CSDN博客
科普文:微服务之技术选型 Spring Cloud Alibaba_阿里巴巴微服务-CSDN博客
科普文:Java基础Spring系列之【微服务系统架构Spring cloud】_java spring cloud-CSDN博客
2. 负载均衡
硬件负载均衡:使用专业的硬件负载均衡设备,如 F5。
软件负载均衡:使用软件解决方案,如 LVS、Nginx、HAProxy 等,将流量分发到后端服务器。
科普文:深入理解负载均衡(四层负载均衡、七层负载均衡)-CSDN博客
科普文:微服务之Spring Cloud 客户端负载均衡组件LoadBalancer替代Ribbon_blockingloadbalancerclient-CSDN博客
3. 缓存
页面缓存:将静态页面缓存到 CDN 或代理服务器中,减少服务器的负载。
数据缓存:使用内存缓存系统,如 Redis、Memcached,将频繁访问的数据缓存到内存中,减少数据库的压力。
数据库缓存:在数据库查询中使用缓存,减少重复查询的开销。
Java web应用性能分析之【高并发之缓存-多级缓存】_java多级缓存-CSDN博客
实战:微服务之Spring Cloud 熔断保护组件Hystrix熔断、请求合并、请求缓存实操_springcloud熔断恢复机制-CSDN博客
科普文:Java基础mybatis系列之【mybatis缓存:一级缓存、二级缓存】-CSDN博客
科普文:深入理解MyBatis 的缓存机制_mybatis 缓存更新机制-CSDN博客
科普文:Redis系列之【Redis 实践及思考】-CSDN博客
科普文:从Redis1.0到Redis7.0的发展历程来理解为什么Redis钟爱单线程_redis版本-CSDN博客
4. 数据库优化
索引优化:为常用查询添加索引,提升查询性能。
分库分表:将大表拆分为多个小表,或将数据库按业务分为多个子库,减小单个数据库的负载。
读写分离:主从复制,主库处理写操作,从库处理读操作,提升数据库的读写性能。
事务优化:尽量减少事务的范围和时间,避免长时间占用数据库资源。
科普文:软件架构数据库系列之【MySQL前世今生及其体系结构概叙】_mysql 架构发展-CSDN博客
科普文:软件架构数据库系列之【MySQL5.6体系结构】-CSDN博客
科普文:软件架构数据库系列之【MySQL三高架构设计:高并发、高性能、高可用】_高性能mysql-CSDN博客
科普文:软件架构数据库系列之【MySQL查询优化器中的优化策略optimizer_switch--ICP索引下推】_查询优化器 optimizer-CSDN博客
科普文:软件架构数据库系列之【MySQL高可用方案选型参考:优化、安全与高可用性】-CSDN博客
科普文:微服务之微服务改造【重构—技术方案选型】_微服务化改造-CSDN博客
5. 网络优化
CDN 加速:使用内容分发网络(CDN),将静态资源分发到靠近用户的节点,减少网络延迟。
压缩传输:使用 gzip 或其他压缩算法压缩数据,减少传输的数据量。
科普文:软件架构网络系列之【高性能网络/存储之基础:TCP/IP、DMA、RDMA、Infiniband、RoCE、iWARP】-CSDN博客
Java web应用性能分析之服务端慢[网络慢]_如何排查应用服务慢-CSDN博客
Java web应用性能分析服务端慢之Nginx慢_nginx 代理慢-CSDN博客
6. 应用层优化
代码优化:优化代码逻辑,减少不必要的计算和 I/O 操作。
连接池:使用数据库连接池、线程池等,重用连接和线程,减少连接建立的开销。
资源复用:尽量复用已有资源,避免频繁创建和销毁对象。
Java web应用性能分析之服务端慢和优化概叙_cpu飙高java-CSDN博客
科普文:微服务之微服务性能优化【后端接口性能优化 】操作说明_微服务性能调优-CSDN博客
7. 并发控制
限流:对系统的请求进行限流,避免瞬时大流量冲击系统。
熔断:在检测到系统负载过高时,自动熔断部分服务,防止系统崩溃。
降级:在系统负载过高或部分服务不可用时,自动降级非核心功能,保证核心功能的正常运行。
科普文:分布式架构中的三高:高并发、高性能、高可用_分布式高并发-CSDN博客
科普文:软件架构之【并发理论基础:并发问题产生的三大根源】-CSDN博客
科普文:Java基础系列之【Java并发基本概念】-CSDN博客
Java web应用性能分析之【高并发之降级】_web应用系统降级-CSDN博客
Java web应用性能分析之【高并发之限流】_web服务限流-CSDN博客
Java web应用性能分析之【高并发之缓存-多级缓存】_java多级缓存-CSDN博客
8. 前端优化
资源合并:合并 CSS 和 JavaScript 文件,减少请求次数。
懒加载:对图片和其他资源使用懒加载,减少初始加载时间。
减少重绘和重排:优化 DOM 操作,减少浏览器的重绘和重排次数。
Java web应用性能分析服务端慢之前端页面慢_前端页面加载性能分析-CSDN博客
https://blog.csdn.net/Rookie_CEO/article/details/137948749
9. 安全性优化
防止 DDoS 攻击:使用防火墙和其他安全措施,防止分布式拒绝服务攻击。
身份验证和授权:确保只有合法用户可以访问系统,防止恶意请求对系统造成负载。
Java web应用性能分析之安全加固_java web jar 加固-CSDN博客
Java web应用性能分析之安全问题处理_javaweb项目安全性问题处理-CSDN博客
科普文:软件架构设计之【信息安全防护方案设计】_系统信息安全防护软件开发-CSDN博客
科普文:软件架构Linux系列之【安全加固:高危端口】_linux高危端口-CSDN博客
科普文:软件架构设计之【API接口安全设计】_软件系统 接口数据加密-CSDN博客
科普文:Java基础系列之【BCrypt、Argon2、PBKDF2 安全地存储和验证密码】-CSDN博客
科普文:软件架构设计之【网络安全:跨站请求伪造CSRF(Cross-site request forgery)原理和防御】-CSDN博客
科普文:软件架构设计之【如何确保JWT的安全性:伪造、篡改、窃取?】_java jwt 防伪造、篡改、截取原理-CSDN博客
科普文:软件架构设计之【网络安全:跨站点脚本xss攻击方式和防御方法】-CSDN博客
科普文:软件架构设计之【网络安全:web应用常见的网络攻击方式和防御方法】_49443303000000034839-CSDN博客
科普文:软件架构设计之【网络安全:漏洞攻击方式和防御方法】-CSDN博客
科普文:软件架构设计之【网络安全:分布式拒绝服务DDoS攻击方式和防御方法】-CSDN博客
科普文:软件架构设计之【网络安全:Redirect重定向攻击方式和防御方法】-CSDN博客
Java web应用性能分析之【漏洞/缺陷处理】_拒绝服务stringbuilder漏洞-CSDN博客
科普文:软件架构Nginx系列之【详解Nginx防CC和DDos攻击】_nginx ddos-CSDN博客
Java web应用性能分析之漏洞和网络攻击_浪潮 漏洞-CSDN博客
10.服务器优化
选择合适的硬件:要考虑选择适合的硬件设备。服务器的性能受到硬件配置的影响。服务器的处理器、内存、硬盘等组件都应该选择性能较好的型号和品牌。
合理规划硬件的配置,例如使用RAID阵列提高硬盘的读写速度,使用SSD硬盘代替传统机械硬盘可以大大提升服务器的响应速度。
科普文:Linux服务器性能调优概叙_linux调优-CSDN博客
科普文:linux服务器性能调优之内核参数_linux内核参数查看-CSDN博客
科普文:Linux服务器磁盘的 I/O 性能优化思路_fio slat clat-CSDN博客
科普文:Linux 服务器性能调优实战:CPU和内存_服务器调优-CSDN博客
科普文:了解RAID独立冗余磁盘阵列_磁盘冗余阵列-CSDN博客
11. 性能监控与调优
监控:使用监控工具(如 Prometheus、Grafana)实时监控系统性能,及时发现性能瓶颈。
日志分析:通过日志分析发现性能问题,优化代码和系统配置。
性能测试:定期进行性能测试,模拟高并发场景,提前发现和解决性能问题。
Java web应用性能分析之【Linux服务器性能监控分析概叙】_web应用 cpu密集型-CSDN博客
科普文:MySQL 数据库巡检_mysql数据库巡检-CSDN博客
通过以上优化思路,可以有效提升高并发系统的性能和可靠性,确保系统在高负载情况下依然能够稳定运行。
CPU核心
CPU核心通常指的是中央处理单元(CPU)内部的独立处理单元。
CPU是计算机的大脑,负责解释指令和处理数据。
在设计上,一个CPU可以包含多个核心,每个核心可以独立执行任务。
核心数量的增加可以让CPU同时处理更多的任务,从而提高整体的性能。
上图这个CPU可描述为:单CPU 4核心 (每核就只有1线程)。4核 指的是物理核心(物理概念)。4线程(线程数是一个逻辑概念)。(暂定本cpu不支持超线程技术)
以下是一些关于CPU核心的关键点:
- 核心数量:CPU核心的数量可以是双核、四核、八核等。核心数越多,理论上CPU能够同时处理的任务就越多。
- 性能提升:多核心CPU能够在不增加处理器主频的情况下,通过并行处理提高计算性能,尤其是在进行多任务处理或复杂计算时。
- 技术发展:随着技术的发展,CPU厂商通过SMP(对称多处理)技术将多个核心集成到单个CPU中,从而提高了处理能力。这种多核心的设计使得现代CPU能够高效地处理多线程任务。
- 核心与线程:每个CPU核心可以支持一个或多个线程。线程是CPU调度的基本单位,多线程技术允许每个核心同时处理多个任务,进一步提高了效率。
- 计算机性能:CPU的核心数量只是影响计算机性能的众多因素之一。其他因素如主频、缓存大小、架构设计等也对性能有重要影响。
C:\Users\Admin>wmic
wmic:root\cli>cpu get
AddressWidth Architecture AssetTag Availability Caption Characteristics ConfigManagerErrorCode ConfigManagerUserConfig CpuStatus CreationClassName CurrentClockSpeed CurrentVoltage DataWidth Description DeviceID ErrorCleared ErrorDescription ExtClock Family InstallDate L2CacheSize L2CacheSpeed L3CacheSize L3CacheSpeed LastErrorCode Level LoadPercentage Manufacturer MaxClockSpeed Name NumberOfCores NumberOfEnabledCore NumberOfLogicalProcessors OtherFamilyDescription PartNumber PNPDeviceID PowerManagementCapabilities PowerManagementSupported ProcessorId ProcessorType Revision Role SecondLevelAddressTranslationExtensions SerialNumber SocketDesignation Status StatusInfo Stepping SystemCreationClassName SystemName ThreadCount UniqueId UpgradeMethod Version VirtualizationFirmwareEnabled VMMonitorModeExtensions VoltageCaps
64 9 To Be Filled By O.E.M. 3 Intel64 Family 6 Model 142 Stepping 9 252 1 Win32_Processor 2400 8 64 Intel64 Family 6 Model 142 Stepping 9 CPU0 100 206 512 3072 0 6 45 GenuineIntel 2400 Intel(R) Core(TM) i3-7100U CPU @ 2.40GHz 2 2 4 To Be Filled By O.E.M. FALSE BFEBFBFF000806E9 3 CPU TRUE To Be Filled By O.E.M. U3E1 OK 3 Win32_ComputerSystem DESKTOP-IT2ALVP 4 51 TRUE TRUE
wmic:root\cli>
- NumberOfCores:表示CPU核心数
- NumberOfLogicalProcessors:表示CPU线程数
多核 是指一个CPU有多个核心处理器,处理器之间通过CPU内部总线进行通讯。
多CPU是指简单的多个CPU工作在同一个系统上,多个CPU之间的通讯是通过主板上的总线进行的。
物理核
- 物理核数量=cpu数(机子上装的cpu的数量)*每个cpu的核心数
虚拟核
- 所谓的4核8线程,4核指的是物理核心。通过超线程技术,用一个物理核模拟两个虚拟核,每个核两个线程,总数为8线程。
- 在操作系统看来是8个核,但是实际上是4个物理核。
- 通过超线程技术可以实现单个物理核实现线程级别的并行计算,但是比不上性能两个物理核。
单核CPU
单核就是CPU集成了一个运算核心,在工作期间只能执行某一个程序,处理多个程序时,只能分时处理。现在推出的CPU基本没有单核CPU了。(多用于个人电脑)
多核CPU
在一颗芯片里集成了多个CPU运算核心,相当于多个单核CPU同时工作。因此,多核处理器可以同时处理多个程序,而不用等上一个程序完成。(多用于服务器)
科普文:软件架构Linux系列之【AMD砍杀Intel的利器:Zen微架构CPU锐龙和霄龙】-CSDN博客
单核cpu和多核cpu
- 都是一个cpu,不同的是每个cpu上的核心数
- 多核cpu是多个单核cpu的替代方案,多核cpu减小了体积,同时也减少了功耗
- 一个核心只能同时执行一个线程
进程/线程
注意下方语句中的 主体:操作系统、CPU
进程
进程:是操作系统(OS)进行资源(CPU、内存、磁盘、IO、带宽等)分配的最小单位;
是OS对正在运行的程序的一种抽象,是应用程序的执行实例,每个进程是由私有的虚拟地址空间、代码、数据和其它各种系统资源组成。
打开一个浏览器、一个聊天窗口分别是一个进程。进程可以有多个子任务,如聊天工具接收消息、发送消息,这些子任务是线程。
资源分配给进程,线程共享进程资源。
线程
线程:是CPU调度和分配的基本单位。
一个进程可由多个线程的执行单元组成,每个线程都运行在同一进程的上下文中,共享同样的代码和全局数据。
每个进程至少有一个主执行线程,它无需由用户主动创建,一般由系统自动创建。系统创建好进程后,实际上就启动了执行该进程的执行主线程,执行主线程以函数地址形式,即程序入口函数(如 main函数),将程序的启动点提供给操作系统。主执行线程终止了,进程也就随之终止。
线程数 是一种逻辑概念,是模拟出的CPU核心数。
一个进程有多个线程。线程可能分为内核态线程和用户态线程。
线程的特点包括:
- 轻量级:相比于进程,线程是更轻量级的执行单元。创建和销毁线程的开销较小,可以在短时间内创建大量线程。
- 共享资源:线程在同一个进程内共享进程的内存空间和系统资源。这意味着多个线程可以直接访问和修改同一份数据,更容易实现数据共享和通信。
- 并发执行:多个线程可以并发执行,实现任务的同时进行。不同线程之间可以按照特定的调度算法分配CPU时间片,从而实现并发处理。
- 上下文切换:由于线程是并发执行的,操作系统需要在不同线程之间进行上下文切换。上下文切换是指将一个线程的执行状态保存起来,并恢复另一个线程的执行状态,这个过程会带来一定的开销。
- 线程同步:多个线程访问共享资源时可能会出现竞态条件和数据不一致的问题。为了保证数据的一致性和正确性,需要使用线程同步机制,如互斥锁、信号量、条件变量等。
- 可以实现并行性:在多核处理器上,多个线程可以并行执行,提高程序的执行效率。通过线程的并行执行,可以将任务划分为多个子任务并同时进行处理,加快任务的完成速度。
总而言之,线程是一种轻量级的执行单元,它可以并发执行并共享进程的资源。通过合理地使用线程,我们可以充分发挥计算机的处理能力,提高程序的执行效率和响应速度。
线程是进程内的执行单元,它是CPU调度的基本单位。每个线程都运行在进程的上下文中,共享进程的内存空间和系统资源。线程之间可以直接共享数据,因此线程间通信更加高效。
内核态线程
优点:一个进程的多个线程可以分配到多个CORE核心同时执行,并且由于内核级线程只有很小的数据结构和堆栈,切换速度快,本身也可以用多线程技术实现提高系统的运行速率。
缺点:线程在用户态的运行,而线程的调度和管理在内核实现,在控制权从一个线程传送到另一个线程需要用户态到内核态再到用户态的模式切换,比较占用系统资源。
用户态线程
优点:线程的调度不需要内核直接参与,控制简单,可以在不支持线程的操作系统中实现
缺点:没有办法使用多核心并行执行
协程
协程(Coroutine)是一种用户态的轻量级线程,它允许在单个线程内创建多个执行流程,并在这些执行流程之间进行切换。协程的切换开销非常小,因为它是由用户态的代码手动控制的,不需要操作系统介入。协程特别适合于I/O密集型任务,因为它可以在I/O操作时切换到其他协程,从而充分利用CPU时间12。
虚拟线程
虚拟线程(Virtual Threads)是Java 11引入的一个新概念,它是基于Java线程的轻量级实现。虚拟线程共享相同的线程栈和执行环境,但每个虚拟线程都有自己的本地变量和调用栈。虚拟线程的创建和管理由Java虚拟机(JVM)自动处理,用户不需要手动管理。虚拟线程适用于需要大量并发处理但又不希望创建太多真实线程的场景34。
伪线程
伪线程(Fiber)通常指在用户空间中实现的轻量级线程,它们不直接映射到操作系统级别的线程。伪线程的调度和切换完全由用户程序控制,不需要操作系统介入。伪线程适用于需要高并发但又不希望消耗过多系统资源的场景5。
纤程
纤程(Fiber)通常指在用户模式下运行的轻量级线程,比伪线程更轻量级。纤程的调度和切换完全在用户空间完成,不需要操作系统介入,因此开销非常小。纤程适用于需要高并发处理且对性能要求较高的场景5。
总结
协程、虚拟线程、伪线程和纤程的区别主要在于它们的定义、实现方式、调度方式以及适用场景。
- 协程:用户态的轻量级线程,手动控制切换,适合I/O密集型任务。
- 虚拟线程:基于Java线程的轻量级实现,由JVM自动管理,适合需要大量并发处理但不希望创建太多真实线程的场景。
- 伪线程:在用户空间实现的轻量级线程,调度和切换由用户程序控制,适用于高并发且对系统资源消耗要求低的场景。
- 纤程:在用户模式下运行的轻量级线程,调度和切换完全在用户空间完成,适用于高并发且对性能要求较高的场景。
进程/线程关系
进程和线程的关系:进程可以简单理解为一个容器,有自己独立的地址空间,其内部的各个线程共享该地址空间。
其实严格讲应该是线程能够获得CPU资源,进程对CPU资源的获取也是体现在线程上的。至于CPU内核数,和进程线程没直接关系。操作系统(OS)可以把某个进程部署在某个CPU核上,当然这要取决于系统设计。
线程是CPU调度和分配的最小单位,操作系统会根据进程的优先级和线程的优先级去调度CPU。一个计算机可以并发(同时)的线程数,等于计算机上的逻辑处理器的个数(CPU个数 *每个CPU核心数 *每个内核线程数
)。
进程、线程是操作系统调度的,进程本身不会负责调度线程。在操作系统看来,线程和进程其实差不多,不同点是线程是迷你的进程,并且进程可以包含多个线程。
对比 | 进程 | 线程 |
---|---|---|
定义 | 进程是程序运行的一个实体的运行过程,是系统进行资源分配和调配的一个独立单位 | 线程是进程运行和执行的最小调度单位 |
系统开销 | 创建撤销切换开销大,资源要重新分配和收回 | 仅保存少量寄存器的内容,开销小,在进程的地址空间执行代码 |
拥有资产 | 资源拥有的基本单位 | 基本上不占资源,仅有不可少的资源(程序计数器,一组寄存器和栈) |
调度 | 资源分配的基本单位 | 独立调度分配的单位 |
安全性 | 进程间相互独立,互不影响 | 线程共享一个进程下面的资源,可以互相通信和影响 |
地址空间 | 系统赋予的独立的内存地址空间 | 由相关堆栈寄存器和和线程控制表TCB组成,寄存器可被用来存储线程内的局部变量 |
线程切换
-
CPU给线程分配时间片(也就是分配给线程的时间),执行完时间片后会切换都另一个线程。
-
切换之前会保存线程的状态,下次时间片再给这个线程时才能知道当前状态。
-
从保存线程A的状态再到切换到线程B时,重新加载线程B的状态的这个过程就叫上下文切换。
-
而上下切换时会消耗大量的CPU时间。
线程开销
- 上下文切换消耗
- 线程创建和消亡的开销
- 线程需要保存维持线程本地栈,会消耗内存
程序与进程、线程的关系
程序 只是一组指令的有序集合,它本身没有任何运行的含义,只是一个静态的实体。
而进程则不同,它是程序在某个数据集上的执行(即 进程是程序的一次执行),是一个动态的实体,有自己的生命周期,因创建而产生、因调度而运行、因等待资源或事件而被处于等待状态、因任务完成而被撤销,反映的是一个程序在一定的数据集上运行的全部动态过程。
进程和程序并不是一一对应的:一个程序执行在不同的数据集上就成为不同的进程,可以用进程控制块来唯一地标识每个进程。这是程序无法做到的,因为程序没有和数据产生直接的联系,即使是执行不同的数据的程序,但它们的指令的集合依然是一样的,因此无法唯一地标识出这些运行在不同数据集上的程序。
一般来说,一个进程肯定有一个与之对应的程序,而且只有一个。而一个程序有可能没有与之对应的进程(因为它没有执行)、也可能有多个进程与之对应(运行在不同的数据集上)。
不同的进程可以执行同一段程序,比如读取同一个文件数据,它们的读取函数的代码是相同的,并被2个进程或线程运行了。
一般情况下,写一个程序,没有单独开线程,那么默认这个程序的一次运行就是一个单进程;而如果调用了fork,这时将会有2个进程,调用thread,则这个进程就会有2个线程。
进程是一个实体,每一个进程都有它自己的内存地址段(heap、stack等),进程是执行中的程序。
程序是一个没有生命的实体,只有处理器赋予程序生命时,才能成为一个活动的实体。
线程,程序执行的最小单元,每个程序都至少有一个线程,若程序只有一个线程,那就是它程序本身。单线程的进程可以简单地理解为只有一个线程的进程。一个进程在同一时间只做一件事,但有了多线程后,一个进程同一时间可以做多件事,每个线程可以处理不同的事务。无论系统有几个CPU,其实进程运行在单CPU上,多线程也可以是进程并发处理多个事务。一个线程阻塞不会影响另一个线程。
多线程的进程可以尽可能地利用系统CPU资源,但也不是线程越多越好,线程越多,CPU分配给每个线程的时间就越少。
线程 包含了表示进程内执行环节所必需的信息:标识线程的线程ID、一组寄存器值、栈、调度优先级和策略、信号屏蔽字、errno变量、线程私有数据。
对于内存而言,堆内存、代码区一般属于一个进程,但是栈却是属于一个线程的,且每个线程拥有一个独立的栈。
errno也是属于单个线程的,每个线程中的errno是独立的。
进程内所有信息对于线程是共享的,包括执行代码、全局变量、堆内存、栈、文件描述符。
总结:
进程和线程都是一个时间段的描述,是CPU工作时间段的描述:
- 进程就是上下文切换的程序执行时间总和 = CPU加载上下文+CPU执行+CPU保存上下文
- 线程是共享了进程的上下文环境,的更为细小的CPU时间段。
CPU处理程序
单核CPU处理程序
在单CPU计算机中,有一个资源是无法被多个程序并行使用的:CPU。
单进程多线程处理:
在一个程序里,有两个功能:听歌、发送消息,这就是单进程2线程。如果听歌线程获取了锁,那么这个线程将获取CPU的运行时间,其他线程将被阻塞。但CPU始终处于运行状态,影响计算时间的其实只是加锁、解锁的时间,并不会发生CPU空闲的现象,CPU利用率100%。
线程阻塞:一般是被动的,在抢占资源中得不到资源,被动的挂起在内存,等待某种资源或信号将它唤醒。(释放CPU,不释放内存)
多进程处理:
将听歌、发消息分别写出两个独立的程序,独立运行,与上面不同的是,如果进程间需要通信,比如交换数据,则会需要很多步骤,效率低。
多核CPU处理程序
单进程多线程处理:线程可以跨核处理,进程之间则不能,如同支付宝不能访问QQ一样(安全性)。
跟单核对比:如果A核处理听歌线程阻塞,B核空闲,则CPU工作效率下降一半;没有阻塞时,QQ的A线程听歌、B线程发消息,多核CPU效率比单核快很多。
多进程多线程处理:不同的程序,不可能一个进程融合QQ、支付宝、浏览器等。
总结:
1、单CPU中进程只能是并发,多CPU计算机中进程可以并行。
2、单CPU单核中线程只能并发,单CPU多核中线程可以并行。
3、无论是并发还是并行,使用者来看,看到的是多进程,多线程。
多核下线程数量选择
计算密集型
- 程序主要为复杂的逻辑判断和复杂的运算。
- cpu的利用率高,不用开太多的线程,开太多线程反而会因为线程切换时切换上下文而浪费资源。
IO密集型
- 程序主要为IO操作,比如磁盘IO(读取文件)和网络IO(网络请求)。
- 因为IO操作会阻塞线程,cpu利用率不高,可以开多点线程,阻塞时可以切换到其他就绪线程,提高cpu利用率。
单核cpu支持多线程吗?
单核CPU支持多线程。(毕竟20年前的939针单核不支持超线程的cpu电脑都能一边玩war3,一边千千静听听歌)
在单核CPU上,虽然只有一个物理处理单元,但通过线程切换和时间片轮转,操作系统可以在不同的线程之间进行切换,从而实现多个线程的并发执行。当一个线程的时间片用完后,操作系统会保存当前线程的状态,然后切换到另一个线程继续执行。这样,多个线程可以交替执行,给用户一种并发执行的感觉。
单核CPU支持多线程的原理
单核CPU通过时间片轮转的方式来实现多线程并发执行。
科普文:软件架构之Linux系列【CPU调度策略】-CSDN博客
科普文:软件架构之Linux系列【操作系统:处理机调度Schedule/Dispatcher】-CSDN博客
时间片是CPU分配给各个任务(线程)的时间,由于时间片非常短,CPU通过不停地切换线程执行。这样,虽然同一时刻只有一个线程在执行,但通过频繁的上下文切换,用户会感觉到多个线程在同时进行。
多线程在单核CPU上的优缺点
优点:
- 提高CPU利用率:通过多线程技术,单核CPU可以在不同线程之间切换,避免某个核心的空闲时间,从而提高整体的利用率。
- 解决线程阻塞问题:在单核CPU上,如果某个线程因为等待资源而阻塞,其他线程可以继续执行,从而提高程序的响应速度。
缺点:
- 上下文切换开销:频繁的上下文切换会增加开销,导致线程之间的切换开销和等待时间增加,从而降低多线程并发执行的效率。
- 效率不如多核CPU:由于单核CPU的物理限制,同一时刻只能有一个线程在执行,多线程的执行效果不如在多核CPU上。
总结
- 提高性能的一种方式:提高硬件水平,处理速度或核心数。
- 另一种方式:根据场景,合理设置线程数,软件上提高cpu利用率。
进程:处理任务多,每个进程都有独立的内存单元,占用CPU资源相对较少。缺点是 进程间切换开销大。进程之间通信就如同两个程序之间的通信。
线程:处理任务相对较少,同时为了处理【并发】,多个线程共享内存单元,占用资源少。线程之间的通信就如同一个程序里的两个函数间通信,在函数里定义一个全局变量,两个线程(两个函数)都能用,线程间共享内存。
同步与异步/阻塞与非阻塞
一、同步与异步
- 同步与异步两个名次是用来表达任务的提交方式。
- 根据进程和函数之间的通信机制,函数可以分为异步和同步。
同步
同步:进程调用函数后,函数执行完成之后,才会有返回值,没有执行完成之前,不会有返回值。(串行)
例子:打开一个程序,我们等待他进行加载,期间不做别的操作,等他打开后再接着使用。
异步
异步:进程调用函数后,函数会直接返回收到(可以理解为:已收到,正在处理),等到处理完成,函数会通过回调或通知的方式,将结果发送给进程。(并行)
例子:当我们打开一个软件,会先进入加载界面,这个时候我们不等待,在加载的时候去打开另一个软件。然后当另一个软件进入加载状态的时候第一个软件就已经加载好,这时候我们可以通过软件的变化或是提示得知第一个软件已经可以使用了。
二、阻塞与非阻塞
- 阻塞与非阻塞是用来表达任务的执行状态
- 根据进程等待函数调用时的状态,函数可以分为阻塞和非阻塞。
阻塞
在得到函数返回值之前,该进程处于挂起状态,不属于工作队列(可运行状态进程组成的队列),不会占用CPU资源。(串行/同步)
非阻塞
进程调用函数之后,无论是否返回结果,进程都会继续运行,进程仍处于可运行状态。(并行/异步)
- 学习了进程的三种状态,他们可以归类为阻塞态与非阻塞态
三、综合使用
1.同步阻塞:
客户揣发送请求给服务揣,此时服务端处理任务时间很久,则客户端则被服务端堵塞了,所以客户端会一直等待服务端的响应,此时客户端不能做其他任何事,服务端也不接受其他客户揣的请求。这种通信机制比较简单租暴,但是效率不高。
举例:
一个进程运行,执行内部函数的时候进程要等待返回结果,这个时候cpu发现你现在在等待,cpu就不给你用了,让你进入阻塞状态。然后你因为在等待返回结果,没有继续运行别的函数,所以你处于同步状态。
2.同步非阻塞:
客户端发送请求给服务端,此时服务端处理任务时间很久,这个时候虽然客户端会一直等待响应,但是服务端可以处理其他的请求,过一会回来处理原先的。这种方式很高效,一个服务端可以处理很多请求,不会在因为任务没有处理完而堵着,所以这是非阻塞的。
举例:
一个进程运行,执行内部函数的时候进程要等待返回结果,这个时候cpu发现你现在在等待,但是他没有直接不给你用,在给你用的同时他也处理别的进程的任务,这个时候就是非阻塞态。但是进程虽然用着cpu,可是因为没收到返回值代码一直停着没继续往下,所以他还是在同步态。
3.异步阻塞:
客户揣发送请求给服务端,此时服务端处理任务时间很久,但是客户端不会等待服务器响应,它可以做其他的任务,等服务器处理完毕后再把结果响应给客户端,客户端得到回调后再处理服务端的响应。这种方式可以避免客户端一直处于等待的状态,优化了用户体验,其实就是类似于网页里发起的ajax异步请求。
举例:
一个进程运行,执行内部函数的时候进程要等待返回结果,这个时候cpu发现你现在在等待,cpu就不给你用了,让你进入阻塞状态。然后这个进程不会一直等待最终的结果,他会继续运行别的函数,当结果出来的时候,通知一下这个进程就好了。因为进程停下来等待结果,所以处理异步状态。
4.异步非阻塞:
客户端发送请求给服务端,此时服务端处理任务时间很久,这个时候的任务虽然处理时间会很久,但是客户端可以做其他的任务,因为他是异步的,可以在回调函数里处理响应;同时服务端是非阻塞的,所以服务端可以去处理其他的任务,如此,这个模式就显得非常的高效了 。
举例:
一个进程运行,执行内部函数的时候进程要等待返回结果,这个时候cpu发现你现在在等待,但是他没有直接不给你用,在给你用的同时他也处理别的进程的任务,这个时候就是非阻塞态。然后这个进程不会一直等待最终的结果,他会继续运行别的函数,当结果出来的时候,通知一下这个进程就好了。因为进程停下来等待结果,所以处理异步状态。
ps:将来使用的基本都是异步非阻塞