【神经风格迁移:全链路压测】33、全链路监控与性能优化最佳实践:Java+Python+AI系统稳定性保障的终极武器

全链路监控与性能优化最佳实践:Java+Python+AI系统稳定性保障的终极武器

开篇导语

在当今的数字化时代,系统的稳定性直接关系到企业的命脉。一次意外的性能暴跌可能导致数百万的损失,一次全链路崩溃甚至能动摇企业的根基。我们进行了压测,看到了曲线,生成了报告,但然后呢?压测数据堆积如山,性能问题依然悬而未决------这是许多团队面临的共同困境。

压测本身不是目的,通过压测发现并解决问题,实现系统优化才是真正的终点。 没有监控的压测如同盲人摸象,没有分析的监控只是数据噪音,没有优化的分析则是纸上谈兵。唯有将监控→分析→优化→验证形成一个紧密的闭环,每一次压力测试才能真正转化为可执行的行动项,成为系统稳定性不断进化的驱动力。

本篇作为系列文章的压轴之作,将聚焦于这个核心闭环。面向全栈工程师与SRE,我们不仅要解决"如何压"的问题,更要深入探讨"如何看"、"如何定"、"如何优"。通过一套完整的工具体系与方法论,结合Java、Python及AI服务的真实场景,您将掌握:

  • 全流程自动化压测执行能力
  • 可视化、立体化的监控体系搭建
  • 从宏观指标到代码行的精准瓶颈定位术
  • 具备成本效益的系统性优化策略

让我们开始这场从数据到决策、从问题到价值的深度之旅。


章节一:全链路压测执行框架

一个可靠、高效且智能的压测执行框架,是性能工程的地基。它需要超越简单的脚本执行,具备场景编排、数据流管理、分布式协调等高级能力。

1.1 PressureTestRunner高级特性

我们设计的PressureTestRunner核心框架,旨在解决传统压测工具灵活性差、维护成本高、与监控体系脱节的问题。

场景编排与依赖控制

真实业务场景往往由多个有序或并发的用户行为组成。框架通过YAML或DSL描述复杂的测试场景。

yaml 复制代码
scenarios:
  - name: "AI图片生成峰值场景"
    steps:
      - action: "login" # 前置登录
        user_proportion: 100%
      - action: "upload_image" # 并发上传
        user_proportion: 80%
        think_time: "normal(2,0.5)" # 正态分布思考时间
      - action: "query_result" # 轮询查询结果
        loops: 10
        until: "status==SUCCESS"

通过可视化编排界面,测试人员可以像搭积木一样设计业务流程,并设置步骤间的依赖关系,真实模拟用户操作路径。

失败重试与断点续跑

大规模压测中,网络抖动、服务瞬时不可用可能导致部分请求失败。框架提供智能重试机制,对可重试的异常(如连接超时)自动重试N次。更重要的是,在长时间的稳定性压测中,若因故中断,框架支持从最后一个成功的检查点(Checkpoint)恢复,节省宝贵的时间和资源。

多环境配置管理

同一套压测脚本,需要能在开发、测试、预发、生产等不同环境中无缝切换。框架通过Profile管理环境变量、服务端点、数据源等配置。

properties 复制代码
# application-pre.yaml
jmeter.endpoint: "http://pre-jmeter-server:8080"
prometheus.pushgateway: "http://pre-prometheus:9091"
test.data.file: "/data/pre_user_ids.csv"

通过-Dspring.profiles.active=pre一键切换,实现压测资产的环境隔离与复用。

1.2 压测数据流:从产生到洞察

压测产生的海量数据,需要被高效、实时地转化为洞察力。我们的数据流设计如下:
产生JTL原始结果
聚合指标
原始日志
JMeter Master
JTL解析器
实时数据分叉
Prometheus Pushgateway
Elasticsearch
Prometheus
Grafana
可视化仪表板

JMeter → JTL → 解析 → 报告

JMeter作为可靠的压测引擎,生成详细的JTL(JMeter Test Log)文件。我们的解析器会异步消费JTL文件,进行关键指标(响应时间、成功率、吞吐量)的聚合计算,并生成HTML格式的静态报告,用于初步结果速览。

实时指标推送Prometheus

为满足实时监控需求,解析器在聚合的同时,将每秒的QPS、平均响应时间、错误码分布等核心指标,通过Prometheus Pushgateway推送到Prometheus时序数据库。这使得我们能在Grafana上看到与压测进度完全同步的曲线变化。

异常事件标记

当解析器检测到错误率飙升、响应时间超过阈值等异常事件时,会在时序数据中插入一个特殊的事件标记(Event Annotation)。在Grafana图表上,这些标记会以竖线的形式显示,方便后续将性能拐点与系统事件(如代码发布、配置变更)进行关联分析。

1.3 分布式压测优化

当单机无法模拟足够压力时,分布式压测成为必然。但其引入的复杂度需要妥善管理。

Slave节点负载均衡

Controller节点根据各Slave节点的实时负载(CPU、内存)和网络状况,动态分配线程数。例如,为新扩容的、负载较低的Slave分配更多线程,实现压测资源的弹性利用。

网络带宽预估

在压测开始前,框架会运行一个简短的带宽测试,估算在目标RPS(每秒请求数)下所需的总上行/下行带宽。如果超过Slave节点所在机房的出口带宽,则会告警提示,避免因网络瓶颈导致压力上不去,误判为服务端能力问题。

复制代码
预估带宽(Mbps)= (单个请求大小(KB) + 单个响应大小(KB)) * 目标RPS * 8 / 1024

结果汇聚性能

所有Slave的原始结果会实时汇聚到Controller。我们采用增量汇聚压缩传输的策略。Slave节点每10秒将聚合后的增量数据(而非每一笔请求)发送给Controller,并对数据包进行Snappy压缩,极大减轻网络IO压力,避免汇聚过程本身成为瓶颈。


章节二:可视化监控体系搭建

监控是性能优化的眼睛。一个优秀的监控体系应该像飞机的仪表盘,能立体化、多维度地反映系统健康状况,并在异常时精准告警。

2.1 Grafana仪表板设计:从宏观到微观

我们建议构建一个四层监控体系,层层递进,由表及里。
四层监控体系
业务监控
性能监控
资源监控
故障监控
QPS/交易量
成功率
活跃用户/会话
P50/P95/P99/P999 RT
吞吐量
并发数
CPU/内存利用率
GPU利用率/显存
网络IO/磁盘IO
连接池/线程池
错误率/错误类型
超时率
熔断器状态
日志关键错误

1. 业务监控层(顶层)

  • 核心指标:QPS(每秒查询量)、关键业务交易成功率、活跃用户数/会话数。
  • 价值:直接反映系统对用户的价值交付是否正常。这是所有监控中最重要的一环。
  • Grafana配置示例 :使用Stat面板显示当前总QPS和成功率,用Graph面板展示其随时间变化趋势。

2. 性能监控层(核心层)

  • 核心指标P50/P95/P99/P999响应时间、吞吐量、并发处理数。
  • 洞察 :P50反映大多数用户的体验,P95/P99反映长尾用户的体验,P999(千分位)则用于发现极端异常。只关注平均值是性能监控的最大误区
  • Grafana配置技巧:为P99设置一个显眼的阈值线(如200ms),并用不同颜色填充背景,一眼就能看出何时超标。

3. 资源监控层(基础设施层)

  • 核心指标
    • 通用资源:CPU利用率、内存使用率与GC情况、磁盘IOPS和使用率、网络带宽与连接数。
    • Java服务重点:JVM堆内存各分区(Eden, Survivor, Old Gen)使用情况、Full GC频率与耗时、各线程池(Tomcat, HikariCP)活跃/队列线程数。
    • Python/AI服务重点GPU利用率、GPU显存使用量、Python进程内存RSS。
  • 价值:将性能指标与资源消耗关联,判断瓶颈是来自应用代码还是基础设施。

4. 故障监控层(风险层)

  • 核心指标:各类HTTP状态码(5xx, 4xx)错误率、业务自定义错误码频率、接口超时率、熔断器(如Resilience4j, Sentinel)的打开/关闭状态、日志中的ERROR/FATAL级别信息聚合。
  • 价值:快速发现和定位故障点。

2.2 告警规则精细化:从"狼来了"到精准预警

告警疲劳是运维团队的头号敌人。精细化告警的核心是让对的告警,在对的时间,通知对的人

动态阈值(基于历史基线)

静态阈值(如CPU>80%)无法适应业务的潮汐规律。我们采用基于历史同期(如上周同一时间)数据计算的动态基线。

复制代码
告警阈值 = 历史基线值 + 3 * 历史标准差

例如,系统在凌晨的CPU基线为20%,标准差为5%,则告警阈值约为35%。而在晚高峰基线为60%,标准差为10%,告警阈值则为90%。这样既能发现真正异常,又避免了非高峰时段的误报。

分级告警(Warning/Critical)

  • Warning(警告):指标偏离正常范围,但系统仍能运行。例如,P99响应时间超过阈值的80%。通知至企业微信群/钉钉群,引起关注。
  • Critical(严重):指标严重超标,影响用户体验或系统稳定。例如,错误率持续5分钟>1%。触发电话、短信等强通知,并要求立即处理。

告警降噪策略

  • 聚合:5分钟内同一服务的同一告警只发一条。
  • 依赖抑制:当数据库告警时,自动抑制因此产生的大量应用服务告警。
  • 维护期静默:在计划内的发布、压测期间,自动关闭相关告警。

2.3 SkyWalking链路追踪:照亮黑盒

在微服务架构下,一个请求流经数十个服务,传统的监控对此是黑盒。SkyWalking等APM工具提供了分布式链路追踪能力。

跨服务调用追踪

为每个入口请求生成一个唯一的TraceId,并在服务间传递。在SkyWalking UI上,我们可以清晰看到一个用户请求从网关到Web服务,再到多个Java和Python微服务,最后访问数据库的完整路径,以及每个环节的耗时。

慢调用根因分析

当发现某个接口P99过高时,直接钻取(Drill Down)到该时间段内的慢请求Trace列表。点击一个慢Trace,可以直观看到是哪个下游服务或数据库调用拖慢了整个链路。例如,一个AI推理请求慢,追踪显示90%的时间花在了某个Python服务的model.predict()调用上。

依赖拓扑可视化

SkyWalking能够自动绘制实时服务依赖关系图。这张图不仅能展示服务间的调用关系,还能用线条粗细表示流量大小,用颜色表示健康度(红/黄/绿)。它是理解系统架构、评估变更影响范围的利器。


章节三:性能瓶颈定位方法论

当监控告警响起,如何从纷繁的现象中快速定位根因?我们总结出"瓶颈识别四步法"。

3.1 瓶颈识别四步法

定位到异常指标/服务
定位到具体接口
定位到具体代码/资源
第四步:根因确认
资源竞争?
锁/线程池/连接池
计算瓶颈?
算法/序列化/GPU
外部依赖?
下游服务/DB/缓存
第三步:代码级定位
Java: Arthas监控方法耗时
Python: cProfile或py-spy
数据库: 慢查询日志
第二步:链路分析
查看SkyWalking拓扑
分析慢Trace
定位瓶颈服务/接口
第一步:指标异常检测
CPU > 85%?
P99 > 阈值?
错误率飙升?
性能瓶颈定位四步法
输出优化方案

Step1:指标异常检测 -- "哪里不对劲?"

首先查看Grafana仪表板,回答几个关键问题:

  • 资源:是否有服务的CPU持续高于85%?内存是否即将耗尽?GPU利用率是否偏低(<40%)?
  • 性能:哪个接口的P95/P99响应时间超过了SLA阈值?
  • 故障:错误率是否出现陡升?是否有新的错误类型出现?

Step2:链路分析 -- "谁拖了后腿?"

针对Step1发现的异常接口,进入SkyWalking,查找对应时间段的慢调用Trace。分析Trace的火焰图(Flame Graph)或树状图,找到耗时最长的服务间调用或方法块。此时,问题通常被收敛到1-2个具体的服务或数据库调用上。

Step3:代码级定位 -- "哪段代码有问题?"

  • 对于Java服务 :使用Arthas神器。通过trace命令对可疑方法进行埋点,统计其内部调用链中每一步的耗时。

    bash 复制代码
    trace com.example.AIService predict '#cost>100' -n 5
  • 对于Python服务 :使用py-spy进行实时采样分析,无需修改代码,即可生成火焰图,直观展示CPU时间消耗在哪些函数上。

    bash 复制代码
    py-spy top -p <pid> # 实时查看函数耗时排行
  • 对于数据库:检查慢查询日志,找到执行时间过长的SQL。

Step4:根因确认 -- "根本原因是什么?"

结合代码定位和资源监控,确认最终根因。常见模式有:

  • 锁竞争:某个同步方法或数据库行锁被高频竞争。
  • GC问题:频繁的Full GC导致线程暂停。
  • 不合理的配置:数据库连接池过小,线程池队列无限堆积。
  • 算法/模型瓶颈:单次推理计算量过大,或未充分利用批量处理能力。

3.2 Python (AI) 服务优化案例

案例一:GPU利用率低导致吞吐量上不去

  • 现象:压测时,Python模型服务QPS达到瓶颈,但GPU利用率仅为30-40%。

  • 定位 :使用nvidia-smi监控和py-spy分析,发现每个请求都是model.predict(single_input),导致GPU计算核心大量时间空闲,忙于调度。

  • 优化 :引入请求队列和批量预测。

    python 复制代码
    # Before: 单条预测
    @app.post("/predict")
    def predict_single(item: Item):
        result = model.predict([item.data]) # 每次推理只处理一个
        return result[0]
    
    # After: 批量预测
    from queue import Queue
    import threading
    batch_queue = Queue()
    def batch_worker():
        while True:
            items = collect_items_from_queue(batch_queue, timeout=0.1, max_batch=32)
            if items:
                batch_data = [i.data for i in items]
                batch_results = model.predict(batch_data) # 批量推理
                for item, result in zip(items, batch_results):
                    item.future.set_result(result) # 异步返回结果
    
    # 请求处理
    @app.post("/predict")
    async def predict_batch(item: Item):
        loop = asyncio.get_event_loop()
        future = loop.create_future()
        item.future = future
        batch_queue.put(item)
        return await future
  • 效果 :调整batch_size至8或16后,GPU利用率提升至80%+,服务吞吐量提升3-5倍。

案例二:内存泄漏导致服务OOM重启

  • 现象:服务运行数小时后,内存持续增长直至被Kill。

  • 定位 :使用objgraphtracemalloc分析Python对象增长。

    python 复制代码
    import tracemalloc
    tracemalloc.start()
    # ... 执行一段时间或特定操作后 ...
    snapshot = tracemalloc.take_snapshot()
    top_stats = snapshot.statistics('lineno')
    for stat in top_stats[:10]:
        print(stat) # 打印内存占用最大的10行代码
  • 根因:发现是缓存字典未设置过期时间,或某个全局列表在请求中不断追加数据。

  • 优化 :使用weakref、设置缓存上限、或改用LRU缓存(functools.lru_cache)。

3.3 Java服务优化案例

案例一:数据库连接池耗尽

  • 现象 :高峰期大量请求超时,日志中出现HikariPool-1 - Connection is not available, request timed out after 30000ms
  • 定位 :查看HikariCP监控指标:activeConnections接近maximumPoolSizethreadsAwaitingConnection持续增长。
  • 优化
    1. 适当调大连接池 :但非无限调大,需结合DB最大连接数。

      yaml 复制代码
      spring.datasource.hikari:
        maximum-pool-size: 20 # 从10调整为20
        connection-timeout: 3000 # 连接获取超时时间,不宜过长
    2. 优化SQL :用Arthas的watch命令统计慢SQL,添加索引或优化业务逻辑,缩短连接持有时间

    3. 设置合理的超时与回收策略idle-timeout(连接空闲超时)、max-lifetime(连接最大生命周期)。

案例二:线程阻塞导致CPU空闲但RT高

  • 现象:CPU使用率不高,但P99响应时间飙升。

  • 定位 :使用Arthas的thread命令查看所有线程状态,发现大量线程处于BLOCKEDWAITING状态。

    bash 复制代码
    thread -b # 一键找出当前阻塞其他线程的"罪魁祸首"线程
  • 根因 :可能是synchronized方法锁粒度太粗,或锁定了公共资源(如一个静态HashMap)。

  • 优化 :缩小锁粒度,使用ConcurrentHashMap,或将锁分段(Striped Lock)。

案例三:频繁Full GC导致服务卡顿

  • 现象:监控上看到规律的、每几分钟一次的CPU尖峰,且伴随线程停顿,接口出现毛刺。
  • 定位 :开启GC日志分析,或通过Prometheus的jvm_gc_pause_seconds指标确认。
  • 优化
    1. 分析堆转储(Heap Dump):使用MAT或JProfiler分析,找到占据大量内存的对象。

    2. 调整堆内存与GC策略 :对于响应时间敏感的服务,考虑使用G1或ZGC替换CMS/Parallel GC。

      bash 复制代码
      JAVA_OPTS="-Xms4g -Xmx4g -XX:+UseG1GC -XX:MaxGCPauseMillis=200"
    3. 代码优化 :避免创建大对象,优化集合的使用(如避免List.size()为0但capacity很大的情况)。


章节四:双11压测报告深度解读

一份优秀的压测报告,不仅是结果的罗列,更应是一份指导后续行动的"体检报告"和"处方单"。

4.1 报告结构解析:九大章节

我们的标准报告模板包含:

  1. 概览:压测目标、时间、范围、核心结论(通过/不通过)。
  2. 统计摘要:总请求数、平均/峰值QPS、整体成功率、平均响应时间。
  3. 阶段分析:按不同压力阶段(爬坡、峰值、平稳、衰减)分解指标。
  4. SLA达标情况:逐项核对各接口的响应时间、成功率是否满足预设SLA。
  5. 故障与异常:记录压测期间发现的所有问题、错误及其发生阶段。
  6. 监控数据快照:关键Grafana仪表板、SkyWalking链路的截图。
  7. 性能瓶颈分析:结合监控和链路,详细分析定位到的1-3个主要瓶颈点。
  8. 优化建议与行动计划:针对每个瓶颈点,给出具体、可落地的优化建议,并明确负责人和预计完成时间。
  9. 结论与风险:最终结论,以及上线前仍需关注的核心风险点。

4.2 可视化图表解读

QPS趋势图:不应只是平滑曲线。我们需要结合阶段标记,观察在爬坡和峰值阶段,QPS是否按计划达到目标,是否存在抖动或上不去的情况。

成功率柱状图:按服务或接口分组,并区分HTTP状态码(2xx, 4xx, 5xx)。一眼就能看出哪个服务是"薄弱环节"。

响应时间箱线图(或分布直方图) :比单纯的平均值、P99更有信息量。它能展示响应时间的整体分布情况。如果箱体(IQR,四分位距)很短但上边缘(P99)有大量"飞点",说明存在严重的长尾问题,需要重点优化个别慢请求。

资源热力图:用颜色深浅表示不同时间点、不同服务器的CPU/内存利用率。可以清晰看出负载是否均匀,以及资源使用与流量曲线的关联性。

4.3 关键结论提炼

从一份详实的报告中,必须提炼出可供决策的结论:

  • 系统峰值能力 :在满足SLA(如P99<200ms,成功率>99.9%)的前提下,系统可支撑的极限QPS为X。这是扩容和流量调度的依据。
  • 瓶颈服务 :明确指出当前链条中的最短板。例如:"Python算法服务的批量处理能力是本次压测的核心瓶颈。"
  • 最大风险 :评估对稳定性的最大威胁。例如:"服务严重依赖单点GPU卡,该卡故障将导致全线AI服务不可用。" 这会直接推动高可用方案的实施。

实战案例:性能优化闭环

背景:某电商推荐系统,在晚高峰压测中,核心的"猜你喜欢"接口P99响应时间达到25秒,严重超标(SLA要求<2秒)。

问题分析闭环:

  1. 监控(看):Grafana显示,该接口流量高峰时,下游的Python深度学习服务GPU利用率仅60%,但请求队列积压严重。Java调用端大量线程在等待响应。
  2. 分析(定) :SkyWalking追踪显示,耗时全集中在Python服务的模型推理环节。使用py-spy采样,发现predict函数内部,数据预处理和模型前向传播是主要耗时点,且每次只处理1条数据。
  3. 优化(优)
    • 代码优化 :将Python服务的模型推理从单条改为批量(batch_size=8)。
    • 架构优化:在Java调用端与Python服务间增加一个轻量级消息队列(如Redis List),实现异步化调用和请求缓冲,避免HTTP线程阻塞。
    • 配置优化:适当调大Tomcat和HikariCP的最大线程数,以匹配新的异步处理能力。
  4. 验证(验) :优化后重新执行相同场景的压测。
    • 效果 :P99响应时间从25秒降至1.2秒 。GPU利用率提升至90%+
    • 收益 :服务吞吐量(QPS)提升了3倍 ,而服务器和GPU成本保持不变,实现了显著的性价比提升

这个案例完美诠释了"监控→分析→优化→验证"闭环的力量。性能优化不是一次性的"玄学"调整,而是基于数据驱动的、可重复、可验证的工程技术活动。


总结与系列回顾

至此,我们共同完成了"高并发系统稳定性保障"系列的五篇深度之旅。让我们回顾一下这把"终极武器"的全貌:

  1. 架构设计篇:奠定了可扩展、高可用的微服务与数据层基石。
  2. 缓存与池化篇:通过本地与分布式缓存、精细化的连接/线程池管理,极大提升了系统效率和韧性。
  3. 异步与队列篇:利用消息队列和异步编程,解耦系统,削峰填谷,化同步暴击为平滑处理。
  4. 熔断与降级篇:为系统配备了"保险丝"和"备降方案",确保故障被隔离,核心链路永续。
  5. 全链路监控与性能优化篇(本篇):为整个体系装上了"眼睛"和"大脑",实现了从问题感知到根因定位,再到优化验证的完整闭环。

这五部分共同构成了一个完整的稳定性保障体系 。它遵循经典的PDCA(计划-执行-检查-处理)循环:通过压测计划(P)和执行(D),利用监控进行检查(C),最后通过优化进行处理(A),然后开始下一轮更高级别的循环,驱动系统稳定性螺旋式上升。

读者行动清单

  1. 审视你的监控体系:是否覆盖了业务、性能、资源、故障四层?是否还在看"平均值"?
  2. 实践一次闭环优化:选择一个近期出现的性能问题,严格遵循"四步法"走完分析、优化、验证的全过程。
  3. 重构你的压测报告:确保下一次压测报告包含"优化建议与行动计划"章节,推动问题解决。
  4. 工具落地:在测试环境中部署SkyWalking,尝试用Arthas或py-spy诊断一个已知的慢接口。

稳定性之路,道阻且长,行则将至。愿这套组合武器,能助您在复杂的系统世界中,洞若观火,游刃有余。


附录:关键代码与配置

(一) Grafana Dashboard JSON核心配置片段

json 复制代码
{
  "panels": [{
    "title": "服务P99响应时间与QPS",
    "type": "graph",
    "targets": [{
      "expr": "histogram_quantile(0.99, sum(rate(http_server_requests_seconds_bucket{uri=~'$uri'}[5m])) by (le, uri))",
      "legendFormat": "{{uri}} - P99"
    },{
      "expr": "sum(rate(http_server_requests_seconds_count{uri=~'$uri'}[5m])) by (uri)",
      "legendFormat": "{{uri}} - QPS"
    }],
    "thresholds": [{
      "value": 0.2,
      "color": "red",
      "fill": true,
      "op": "gt"
    }]
  }]
}

(二) 性能瓶颈定位Checklist

  • 资源层:CPU/内存/磁盘IO/网络带宽是否饱和?GPU利用率是否>70%?
  • JVM层:Full GC频率是否异常?堆内存各分区是否健康?
  • 线程/连接池:活跃线程数是否达到上限?是否有线程等待连接或锁?
  • 链路追踪:慢Trace中最耗时的环节是哪个服务/方法?
  • 数据库:是否存在慢查询?连接数是否够用?
  • 缓存:缓存命中率是否正常?缓存集群是否过载?

(三) 优化案例代码对比(Python Batch)

python 复制代码
# Before: 同步单条,GPU利用率低
def predict_single(data):
    # 模拟单次推理
    return model.forward(data)

# After: 异步批量,高GPU利用率
import asyncio
from concurrent.futures import ThreadPoolExecutor

executor = ThreadPoolExecutor(max_workers=2) # 专用推理线程

async def predict_batch_async(batch_data_list):
    loop = asyncio.get_event_loop()
    # 将CPU密集的推理任务 offload 到线程池,避免阻塞事件循环
    batch_result = await loop.run_in_executor(
        executor, 
        model.batch_forward, 
        batch_data_list
    )
    return batch_result
相关推荐
萧曵 丶2 小时前
Synchronized 详解及 JDK 版本优化
java·多线程·synchronized
夏幻灵2 小时前
JAVA基础:基本数据类型和引用数据类型
java·开发语言
luoluoal2 小时前
基于python的小区监控图像拼接系统(源码+文档)
python·mysql·django·毕业设计·源码
weixin199701080162 小时前
闲鱼 item_get - 商品详情接口对接全攻略:从入门到精通
java·后端·spring
cike_y3 小时前
Spring-Bean的作用域&Bean的自动装配
java·开发语言·数据库·spring
BoBoZz193 小时前
MotionBlur 演示简单运动模糊
python·vtk·图形渲染·图形处理
qq_12498707533 小时前
基于深度学习的蘑菇种类识别系统的设计与实现(源码+论文+部署+安装)
java·大数据·人工智能·深度学习·cnn·cnn算法
十八度的天空3 小时前
第01节 Python的基础语法
开发语言·python
BoBoZz193 小时前
GradientBackground 比较不同类型的背景渐变着色模式与坐标转换
python·vtk·图形渲染·图形处理