写点什么

并发编程体系概述

  • 2024-11-19
    北京
  • 本文字数:2227 字

    阅读完需:约 7 分钟

作者:京东自有品牌 周振



协程在处理高并发和 I/O 密集型任务时,具有明显的优势,尤其是在编写异步代码时更加简洁和高效。然而,对于 CPU 密集型任务和传统的多任务处理,线程仍然是一个成熟且有效的选择。


选择协程还是线程,取决于具体的应用场景和需求。随着 Kotlin 协程在 Java 生态系统中的普及,越来越多的中间件和框架开始支持协程。


但是并不一定要使用协程,使用基于多线程的分布式并发框架也可以实现类似的效果、如 akka、Spring WebFlux 等。

多线程知识汇总

基础知识

具体可以查找我之前博客: https://blog.csdn.net/Zzhou1990/article/details/106008171


响应式编程

Show me code

获取时间的并发问题


总结起来原因是 System.currentTimeMillis 调用了 gettimeofday()


调用 gettimeofday()需要从用户态切换到内核态;


gettimeofday()的表现受 Linux 系统的计时器(时钟源)影响,在 HPET 计时器下性能尤其差;


系统只有一个全局时钟源,高并发或频繁访问会造成严重的争用


所以中间件在获取时间时候会有一个单例线程。


分析文章地址 http://pzemtsov.github.io/2017/07/23/the-slow-currenttimemillis.html


阿里sentine获取时间工具类


public final class TimeUtil {
private static volatile long currentTimeMillis;
static { currentTimeMillis = System.currentTimeMillis(); Thread daemon = new Thread(new Runnable() { @Override public void run() { while (true) { currentTimeMillis = System.currentTimeMillis(); try { TimeUnit.MILLISECONDS.sleep(1); } catch (Throwable e) {
} } } }); daemon.setDaemon(true); daemon.setName("sentinel-time-tick-thread"); daemon.start(); }
public static long currentTimeMillis() { return currentTimeMillis; }}
复制代码


json 转换的性能问题


    List<VendorAllVo> vendorList = vendorInfoMapper.findVendorList();    log.info("日志输出:{}", JSONUtils.toJSONString(vendorList));
if(log.isInfoEnabled()){ log.info("日志输出:{}", JSONUtils.toJSONString(vendorList)); }
复制代码


class User {    private long id;    private String name;    private String email;}
public User getUserInfoLowPerformance(long userId) { String key = USER_INFO_KEY + ":" + userId; String jsonUser = (String) redisTemplate.opsForValue().get(key); if (jsonUser == null) { return null; } return new Gson().fromJson(jsonUser, User.class); }

public User getUserInfo(long userId) { Map<String, Object> userInfoMap = redisTemplate.opsForHash().entries(key); if (userInfoMap.isEmpty()) { return null; }
user = new User(); user.setId((Long) userInfoMap.get("id")); user.setName((String) userInfoMap.get("name")); user.setEmail((String) userInfoMap.get("email")); //... }
复制代码


循环处理


循环会将低性能代码放大,主要查看以下,使用异步或非核心操作不是必须在响应前完成。


查找数据 O(1)、使用 IO 网络、缓存、磁盘、使用 cpu 等操作


流式编程


流程编程、caffeine 缓存、批处理优化;减少阻塞等待


case 改造案例:50ms -> 15ms

UMP 和泰山

UMP 秒级监控、强大泰山整合了 UMP、链路追踪、硬件监控、负载均衡等,内部优秀的工具帮助监控性能问题;


通过 UMP 秒级监控作为入口,秒级监控需手动开启,限制接口 50 个



Tp99/Tp999;可用率等;下钻查看每个机器的流量,这些可以根据机器配置在 NP 平台调整权重以及负载策略,继续根据机器查看


生态和体系

并发 &IO




并发 &内存 &CPU


JVM 内存模型,不同的 jdk 版本;确保内存可见性和指令重排序的规则、以及线程的调度


JVM gc 参数设置、包括 gc 频率、相关参数线程数


用户态和内核态切换。


并发 &锁


选择不同的锁,会对并发产生比较大的影响;


锁分类 : 互斥锁、自旋锁、读写锁、乐观锁、悲观锁、锁分段(表锁、行锁、间隙锁)、无锁 cas


https://blog.csdn.net/Zzhou1990/article/details/114393298?spm=1001.2014.3001.5501


并发 &中间件


数据库、缓存、断路器(限流、降级、合并)、服务间调用、配置中心、链路追踪、日志、JMQ


基数和标准:一次 Tcp 连接时间、一次 Http 连接时间


如机器配置 4 核 8g mysql, qps 和 tps 响应时间根据 sql 复杂度从几十 ms~ns 不等


如机器配置 8 核 32C redis qps 响应时间从 nms~100ms

其他:

堆外内存


减少 gc、序列化和反序列化。


字节码增加


Ask gpt4.0 字节码增强如何提高代码性能


缓存行


64Kb、Disruptor、伪共享


https://tech.meituan.com/2016/11/18/disruptor.html


类似概念磁盘顺序读写


局部性原理和分支优化


空间局部性优化:使用数组、合理模型结构


较少分支、分支展开、条件合并


性能分析、火焰图 http://jagile.jd.com/shendeng/article/detail/1680


如何写出让 CPU 跑得更快的代码 = 如何写出让 CPU 缓存命中率更高的代码


并发不只是并发,他还是个策略问题:处理数据的时候选择合适的策略,可能数据很快就会跑出来。


问下 chatgpt:从 kafka 架构设计角度说说高并发怎么实现、用户态和内核态、

发布于: 刚刚阅读数: 5
用户头像

拥抱技术,与开发者携手创造未来! 2018-11-20 加入

我们将持续为人工智能、大数据、云计算、物联网等相关领域的开发者,提供技术干货、行业技术内容、技术落地实践等文章内容。京东云开发者社区官方网站【https://developer.jdcloud.com/】,欢迎大家来玩

评论

发布
暂无评论
并发编程体系概述_京东科技开发者_InfoQ写作社区