在现代 Web 开发中,3D 可视化需求日益增长,特别是在 React 生态系统中实现多 3D 场景的展示与交互。本文通过对比两种实现方案,探讨 React 中构建多 3D 场景的最佳实践,分析它们的技术特点、性能表现和适用场景。

方案一:React Three Fiber 组件化方案

采用 @react-three/fiber(RTF)框架,将每个 3D 场景封装为独立的 <Canvas> 组件,充分利用 React 的组件化思想管理场景元素。

方案二:原生 Three.js 多视口方案

直接使用 Three.js 原生 API,通过单一 Canvas 元素手动管理多个视口。所有场景共享同一个渲染器,利用视口裁剪技术实现多场景并行渲染。

此方案特别适合需要呈现大量 3D 元素且对性能要求较高的场景,如产品展示墙或 3D 数据可视化。通过精细的视口管理和资源优化,可在单个 Canvas 中高效渲染数十至上百个独立 3D 场景。

 在Three.js开发中,多场景渲染是一个常见挑战。以商业网站为例,当需要展示多个3D模型时,开发者往往会为每个模型创建独立的Canvas元素和Renderer实例。也就是本文说的方案一。

然而,这种做法会带来两个显著问题:

  1. WebGL上下文数量限制 浏览器通常对WebGL上下文数量设置了8个的上限,超出限制时,系统会自动释放最早创建的上下文。

  2. WebGL资源无法共享 不同WebGL上下文之间不能共用资源。例如,当两个Canvas都需要加载相同的10MB模型和20MB纹理时,这些资源会被重复加载两次。这不仅导致初始化、着色器编译等操作重复执行,而且随着Canvas数量增加,性能问题会愈发严重。

另一种解决方案是在整个背景中使用单一Canvas填充视口,并通过其他元素来模拟"虚拟画布"(virtual canvas)。具体实现方式是:仅在主Canvas中加载一个Renderer,同时为每个virtual canvas创建独立的场景(Scene)。我们只需确保每个virtual canvas的位置准确,THREE.js就能将它们正确渲染到屏幕对应位置。

这种方法仅使用一个Canvas和一个WebGL上下文,既解决了资源共享问题,又避免了WebGL上下文数量限制的风险。 

 方案一:每个场景拥有独立的Canvas组件(@react-three/fiber)

import { useRef, useEffect, useState } from 'react'
import { Canvas, useFrame } from '@react-three/fiber'
import { OrbitControls } from '@react-three/drei'
import * as THREE from 'three'
import { Flex } from 'antd'
import './index.less'
type SceneData = {id: numbergeometry: THREE.BufferGeometrycolor: THREE.Color
}const SceneItem = ({geometry,color,
}: {geometry: THREE.BufferGeometrycolor: THREE.Color
}) => {const meshRef = useRef<THREE.Mesh>(null)useFrame(() => {if (meshRef.current) {meshRef.current.rotation.y += 0.01}})return (<mesh ref={meshRef} geometry={geometry}><meshStandardMaterialcolor={color}roughness={0.5}metalness={0}flatShading/></mesh>)
}const SceneWithControls = ({ sceneData }: { sceneData: SceneData }) => {return (<Canvascamera={{ position: [0, 0, 2], fov: 50 }}gl={{ antialias: true }}style={{ width: '300px', height: '300px' }}><SceneItem geometry={sceneData.geometry} color={sceneData.color} /><hemisphereLight intensity={3} color={0xaaaaaa} groundColor={0x444444} /><directionalLight position={[1, 1, 1]} intensity={1.5} color={0xffffff} /><OrbitControls minDistance={2} maxDistance={5} /></Canvas>)
}const MultipleElementsDemo = () => {const [scenes, setScenes] = useState<SceneData[]>([])useEffect(() => {if (scenes.length === 0) {const geometries = [new THREE.BoxGeometry(1, 1, 1),new THREE.SphereGeometry(0.5, 12, 8),new THREE.DodecahedronGeometry(0.5),new THREE.CylinderGeometry(0.5, 0.5, 1, 12),]const newScenes = Array.from({ length: 10 }, (_, i) => ({id: i + 1,geometry: geometries[Math.floor(Math.random() * geometries.length)],color: new THREE.Color().setHSL(Math.random(), 1, 0.75),}))setScenes(newScenes)}}, [scenes])return (<div className="multi-scene" ><Flex gap={20} wrap >{scenes.map((scene) => (<div key={scene.id} className="list-item"><SceneWithControls sceneData={scene} /><div>Scene {scene.id}</div></div>))}</Flex></div>)
}export default MultipleElementsDemo

代码解析

多Canvas架构

  • 为每个3D场景创建一个独立的<Canvas>组件(共10个)

  • 每个Canvas拥有自己独立的WebGL上下文、场景图和渲染循环

场景数据结构

type SceneData = {id: numbergeometry: THREE.BufferGeometrycolor: THREE.Color
}

存储几何体和颜色等差异化的场景数据

组件结构

  • SceneWithControls:包装单个场景的完整环境(灯光、控制器等)

  • SceneItem:处理单个3D对象的渲染和动画

动态场景生成

Array.from({ length: 40 }, (_, i) => ({id: i + 1,geometry: geometries[Math.floor(Math.random() * geometries.length)],color: new THREE.Color().setHSL(Math.random(), 1, 0.75)
}))

独立动画控制

useFrame(() => {meshRef.current.rotation.y += 0.01 // 每个场景独立动画
})

性能问题

  • 内存消耗:10个+独立WebGL上下文占用大量内存

  • 渲染开销:同时维护10个渲染循环(即使场景不可见)

  • GPU资源:重复创建相似资源(如几何体、材质)

方案二:基于原生 Three.js 的多视口实现

import { useRef, useEffect, useState } from 'react';
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import './index.less';// 场景项类型定义
type SceneItem = {id: number;geometry: THREE.BufferGeometry;color: THREE.Color;position: [number, number];
};// 场景数据初始化
const initializeSceneData = () => {const geometries = [new THREE.BoxGeometry(1, 1, 1),new THREE.SphereGeometry(0.5, 12, 8),new THREE.DodecahedronGeometry(0.5),new THREE.CylinderGeometry(0.5, 0.5, 1, 12),];return Array.from({ length: 40 }, (_, i) => {const row = Math.floor(i / 5);const col = i % 5;return {id: i + 1,geometry: geometries[Math.floor(Math.random() * geometries.length)],color: new THREE.Color().setHSL(Math.random(), 1, 0.75),position: [col * 370 + 40, row * 370 + 40] as [number, number],};});
};// 创建单个场景
const createScene = (scene: SceneItem, material: THREE.MeshStandardMaterial) => {const sceneObj = new THREE.Scene();// 创建几何体网格const mesh = new THREE.Mesh(scene.geometry, material.clone());mesh.material.color = scene.color;sceneObj.add(mesh);// 添加光照sceneObj.add(new THREE.HemisphereLight(0xaaaaaa, 0x444444, 3));const light = new THREE.DirectionalLight(0xffffff, 1.5);light.position.set(1, 1, 1);sceneObj.add(light);return sceneObj;
};// 初始化所有场景
const initializeScenes = (scenes: SceneItem[]) => {const material = new THREE.MeshStandardMaterial({roughness: 0.5,metalness: 0,flatShading: true,});return scenes.map(scene => createScene(scene, material));
};// 更新Canvas位置
const updateCanvasPosition = (container: HTMLDivElement, canvas: HTMLCanvasElement) => {const containerRect = container.getBoundingClientRect();canvas.style.transform = `translateY(${window.scrollY}px)`;canvas.style.top = `${containerRect.top}px`;
};// 清理资源
const cleanupResources = (animationId: number,renderer: THREE.WebGLRenderer,sceneControls: OrbitControls[],sceneObjects: THREE.Scene[]
) => {window.cancelAnimationFrame(animationId);renderer.dispose();// 清理控制器sceneControls.forEach(ctrl => ctrl.dispose());// 清理几何体和材质sceneObjects.forEach(scene => {scene.traverse(obj => {if (obj instanceof THREE.Mesh) {obj.geometry.dispose();if (Array.isArray(obj.material)) {obj.material.forEach(m => m.dispose());} else {obj.material.dispose();}}});});
};const MultiViewportDemo = () => {const canvasRef = useRef<HTMLCanvasElement>(null);const containerRef = useRef<HTMLDivElement>(null);const scenesRef = useRef<HTMLDivElement>(null);const [scenes, setScenes] = useState<SceneItem[]>([]);const rendererRef = useRef<THREE.WebGLRenderer | null>(null);const animationRef = useRef<number>(0);const sceneCamerasRef = useRef<THREE.PerspectiveCamera[]>([]);const sceneControlsRef = useRef<OrbitControls[]>([]);const sceneObjectsRef = useRef<THREE.Scene[]>([]);// 初始化场景数据useEffect(() => {const newScenes = initializeSceneData();setScenes(newScenes);}, []);// 初始化Three.js和滚动处理useEffect(() => {if (!scenes.length || !canvasRef.current || !scenesRef.current || !containerRef.current) return;const canvas = canvasRef.current;const container = containerRef.current;// 初始化渲染器const renderer = new THREE.WebGLRenderer({ canvas,antialias: true,});rendererRef.current = renderer;// 初始化所有场景sceneObjectsRef.current = initializeScenes(scenes);// 渲染函数const render = () => {if (!rendererRef.current) return;const renderer = rendererRef.current;const width = window.innerWidth;const height = window.innerHeight;// 更新渲染器尺寸if (canvas.width !== width || canvas.height !== height) {renderer.setSize(width, height, false);}// 初始清除renderer.setClearColor(0xffffff);renderer.setScissorTest(false);renderer.clear();// 设置公共渲染状态renderer.setClearColor(0xe0e0e0);renderer.setScissorTest(true);// 渲染每个场景scenes.forEach((scene, i) => {const element = scenesRef.current?.children[i] as HTMLElement;if (!element) return;const rect = element.getBoundingClientRect();// 检查是否在可视区域内if (rect.bottom < 0 ||rect.top > window.innerHeight ||rect.right < 0 ||rect.left > window.innerWidth) return;// 计算视口参数const viewportWidth = rect.right - rect.left;const viewportHeight = rect.bottom - rect.top;const left = rect.left;const bottom = height - rect.bottom;// 初始化相机(延迟初始化)if (!sceneCamerasRef.current[i]) {const camera = new THREE.PerspectiveCamera(50, viewportWidth / viewportHeight, 1, 10);camera.position.z = 2;sceneCamerasRef.current[i] = camera;// 初始化控制器const controls = new OrbitControls(camera, element);controls.minDistance = 2;controls.maxDistance = 5;sceneControlsRef.current[i] = controls;}// 更新相机比例const camera = sceneCamerasRef.current[i];camera.aspect = viewportWidth / viewportHeight;camera.updateProjectionMatrix();// 更新控制器sceneControlsRef.current[i].update();// 更新场景动画const mesh = sceneObjectsRef.current[i].children[0] as THREE.Mesh;mesh.rotation.y += 0.01;// 设置视口并渲染renderer.setViewport(left, bottom, viewportWidth, viewportHeight);renderer.setScissor(left, bottom, viewportWidth, viewportHeight);renderer.render(sceneObjectsRef.current[i], camera);});animationRef.current = requestAnimationFrame(render);};// 开始渲染循环render();updateCanvasPosition(container, canvas);// 事件监听器const handleScroll = () => {updateCanvasPosition(container, canvas);};const handleResize = () => {renderer.setSize(window.innerWidth, window.innerHeight, false);updateCanvasPosition(container, canvas);};window.addEventListener('scroll', handleScroll);window.addEventListener('resize', handleResize);// 清理函数return () => {cleanupResources(animationRef.current,renderer,sceneControlsRef.current,sceneObjectsRef.current);window.removeEventListener('scroll', handleScroll);window.removeEventListener('resize', handleResize);};}, [scenes]);return (<div className="multi-scene-container" ref={containerRef}>{/* Three.js画布 */}<canvas ref={canvasRef} id="three-canvas"style={{position: 'fixed',left: 0,width: '100%',height: '100%',zIndex: 0,pointerEvents: 'none', // 允许穿透到下方元素}}/>{/* 视口定位元素 */}<div ref={scenesRef}style={{ position: 'relative',zIndex: 1,width: '100%',}}>{scenes.map((scene) => (<divkey={scene.id}className="scene-viewport"style={{position: 'absolute',left: `${scene.position[0]}px`,top: `${scene.position[1]}px`,width: '300px',height: '300px',pointerEvents: 'auto', // 恢复交互}}><div className="scene-label">Scene {scene.id}</div></div>))}</div>{/* 撑开容器高度 */}<div style={{ height: `${Math.ceil(scenes.length / 5) * 370}px`,width: '100%'}} /></div>);
};export default MultiViewportDemo;

核心实现原理

  1. 单Canvas多视口架构

    // 单个Canvas承载所有渲染
    <canvas ref={canvasRef} style={{ position: 'fixed' }} />
  2. 视口分割技术

    // 为每个场景设置独立的渲染视口
    renderer.setViewport(left, bottom, width, height);
    renderer.setScissor(left, bottom, width, height);
    renderer.render(scene, camera);
  3. 场景管理结构

    const sceneObjectsRef = useRef<THREE.Scene[]>([]); // 存储所有场景
    const sceneCamerasRef = useRef<THREE.PerspectiveCamera[]>([]); // 各场景相机

关键技术实现

  1. 场景初始化

    const initializeScenes = (scenes: SceneItem[]) => {const material = new THREE.MeshStandardMaterial({...});return scenes.map(scene => createScene(scene, material));
    };
  2. 智能渲染优化

    // 只渲染可视区域内的场景
    if (rect.bottom < 0 || rect.top > window.innerHeight) return;
  3. 资源复用机制

    // 共享基础材质
    const material = new THREE.MeshStandardMaterial({...});
    // 各场景使用材质副本
    mesh.material = material.clone();

性能优化策略

  1. 按需渲染

    • 通过getBoundingClientRect()检测视口可见性

    • 不可见场景跳过渲染

  2. 内存管理

    // 组件卸载时清理资源
    const cleanupResources = () => {renderer.dispose();scene.traverse(obj => obj.geometry.dispose());
    };
  3. 滚动优化

    // 同步Canvas位置与页面滚动
    canvas.style.transform = `translateY(${window.scrollY}px)`;

对比传统多Canvas方案的优劣

特性单Canvas多视口方案多Canvas方案
内存占用低(共享上下文)高(多个上下文)
GPU资源利用率
渲染性能优(批量处理)一般
开发复杂度较高较低
最大场景支持数高(100+)低(通常<20)

实现难点及解决方案

  1. 视口同步问题

    • 难点:确保DOM元素位置与3D视口精确匹配

    • 方案:使用getBoundingClientRect()动态计算

  2. 交互冲突

    • 难点:多个OrbitControls的事件处理

    • 方案:为每个控制器绑定独立DOM元素

              const controls = new OrbitControls(camera, element);// element对应每个场景的DOMcontrols.minDistance = 2;controls.maxDistance = 5;sceneControlsRef.current[i] = controls;
  3. 性能瓶颈

    • 难点:大量场景的渲染压力

    • 方案:实施可见性检测和资源复用

完整工作流程

  1. 初始化阶段

    • 创建所有3D场景和材质

    • 设置共享渲染器

  2. 渲染循环

样式文件

.multi-scene {overflow-y: auto;height: 100%;.list-item {display: inline-block;margin: 1em;padding: 1em;box-shadow: 1px 2px 4px 0px rgba(0, 0, 0, 0.25);background-color: white;}
}
* ::marker {display: none;content: '';
}
.multi-scene-container {position: relative;width: 100%;height: 100%;overflow-y: auto;overflow-x: hidden;
}.scene-viewport {box-shadow: 1px 2px 4px 0px rgba(0, 0, 0, 0.25);background: rgba(255, 255, 255, 0.1); /* 半透明背景 */pointer-events: all; /* 确保能接收交互事件 */
}.scene-label {color: #888;font-family: sans-serif;font-size: 1rem;padding: 0.5em;text-align: center;user-select: none; /* 防止文字被选中 */
}#three-canvas {display: block;outline: none; /* 移除焦点边框 */
}

核心技术对比

1. 实现理念差异

维度React Three Fiber 方案原生 Three.js 方案
编程范式声明式编程,符合 React 思维命令式编程,手动控制渲染流程
抽象层级高抽象,隐藏 Three.js 底层细节低抽象,直接操作 Three.js API
代码风格组件化,JSX 语法描述 3D 场景函数式,手动管理 3D 对象生命周期

React Three Fiber 将 3D 场景描述为 React 组件树,例如用<mesh>标签表示网格,<hemisphereLight>表示光源,这种方式对 React 开发者更友好;而原生方案则需要手动创建THREE.SceneTHREE.Mesh等对象,更接近 Three.js 的原生开发模式。 

 渲染架构对比

方案一:每个场景拥有独立的Canvas组件(@react-three/fiber)

采用 "多 Canvas" 架构,每个场景对应独立的<Canvas>组件,拥有自己的渲染器、相机和渲染循环。这种架构的优势是隔离性好,单个场景的崩溃不会影响其他场景,但资源开销较大。

  • 使用 React Three Fiber(RTF)的声明式 API,每个场景是独立的<Canvas>组件。
  • 每个场景有自己的渲染器、相机和控制器,相互隔离。
  • 利用 RTF 的useFrame钩子实现动画循环。

方案二:基于原生 Three.js 的多视口实现

采用 "单 Canvas 多视口" 架构,所有场景共享一个渲染器,通过setViewport()setScissor()方法在不同区域渲染不同场景。这种架构资源利用率更高,渲染性能更优,但需要手动处理场景隔离。

  • 使用单个全局 Canvas,通过setViewportsetScissor手动管理多个视口。
  • 所有场景共享同一个渲染器,手动控制每个场景的渲染位置。
  • 使用requestAnimationFrame手动实现动画循环。

性能表现对比

在场景数量较少时(如 10 个以内),两种方案性能差异不明显;但当场景数量增加到 40 个时,差异开始显现:

方案一40个模型

可以看到方案1的前24个模型场景没有渲染出来,从25个模型到后面才渲染出来

 方案二40个模型

方案2轻轻松松

  • 内存占用:React Three Fiber 方案由于多个渲染器并存,内存占用约为原生方案的 3-4 倍
  • 帧率表现:原生方案在 40 个场景时仍能保持 60fps,而 React Three Fiber 方案可能降至 30-40fps
  • 渲染效率:原生方案通过视口裁剪只渲染可见区域,而 React Three Fiber 会渲染所有 Canvas,包括不可见区域

原生方案的性能优势源于:

  • 共享渲染上下文,减少 GPU 资源切换
  • 集中式渲染循环,避免多个 requestAnimationFrame 冲突
  • 手动控制渲染时机,可实现按需渲染

 开发效率与维护性

  • React Three Fiber 方案

    • 开发效率高,组件化复用性好
    • 与 React 生态融合自然,可直接使用 hooks 管理动画和交互
    • 学习曲线平缓,React 开发者可快速上手
  • 原生 Three.js 方案

    • 需手动处理大量底层逻辑(如视口计算、资源清理)
    • 代码量更大,需要更多 Three.js 专业知识
    • 维护成本高,需手动协调多个场景的渲染状态

适用场景分析

适合使用 React Three Fiber 的场景

  1. 中小型 3D 应用:场景数量较少(<20 个),对性能要求不极致
  2. 快速原型开发:需要快速搭建可交互的 3D 演示
  3. React 深度集成:需要与 React 状态管理(如 Redux)、表单系统深度集成
  4. 团队技术栈:团队以 React 开发者为主,Three.js 经验有限
  5. 复杂交互场景:需要利用 React 生态的 UI 组件(如菜单、表单)与 3D 场景结合

适合使用原生 Three.js 的场景

  1. 大型 3D 应用:场景数量多(>20 个),对性能要求高
  2. 资源受限环境:需要在低配置设备上运行
  3. 精细控制需求:需要自定义渲染管线、着色器或高级优化
  4. 视口复杂布局:需要实现不规则排列、动态大小的 3D 视口
  5. Three.js 专业团队:团队拥有丰富的 Three.js 经验

总结与最佳实践建议

两种方案各有优劣,没有绝对的好坏,选择时应根据实际需求权衡:

  1. 优先选择 React Three Fiber

    • 项目周期短,需要快速交付
    • 场景数量少,交互不复杂
    • 团队以 React 开发者为主
  2. 考虑原生 Three.js

    • 场景数量多(>20 个)
    • 对性能和资源占用有严格要求
    • 需要深度定制 Three.js 渲染流程
  3. 混合策略

    • 核心复杂场景使用原生 Three.js 保证性能
    • 周边简单场景使用 React Three Fiber 加速开发
    • 通过react-three-fiberextend API 实现原生 Three.js 功能集成

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

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

相关文章

React性能优化终极指南:memo、useCallback、useMemo全解析

掌握 React.memo、useCallback、useMemo 的正确使用姿势&#xff0c;让你的 React 应用性能飞起来&#xff01; &#x1f3af; React.memo 作用 React.memo 是一个高阶组件&#xff0c;用于函数组件&#xff0c;通过浅比较 props 的变化来决定是否重新渲染。如果 props 没有变…

借助 VR 消防技术开展应急演练,检验完善应急预案​

应急演练是企业应对火灾事故的重要手段&#xff0c;而 VR 消防技术的应用&#xff0c;为应急演练带来了全新的体验和更高的效率。VR 消防技术通过虚拟现实技术模拟逼真的火灾场景&#xff0c;让参与者能够身临其境地感受火灾发生时的紧张氛围。某知名物流企业&#xff0c;仓库众…

【电赛学习笔记】MaxiCAM 项目实践——二维云台追踪指定目标

前言 本文是对视觉模块MaixCam实现二维云台人脸跟踪_哔哩哔哩_bilibili大佬的项目实践整理与拓展&#xff0c;侵权即删。 单路舵机基本控制 #导入必要模块 from maix import pwm, time , pinmap#定义全局变量&#xff0c;设初值 SERVO_FREQ 50 #主频 SERVO_MIN_DUT…

深入解析 ArkUI 触摸事件机制:从点击到滑动的开发全流程

摘要 随着 HarmonyOS NEXT 的不断发展&#xff0c;ArkUI 逐渐成为主流的 UI 构建方式。而用户交互在任何应用中都是基础而又关键的一环&#xff0c;如何利用 ArkUI 提供的触摸事件机制&#xff0c;如 onTouch、onClick、onSwipe 等&#xff0c;来实现自然、顺滑、用户友好的交互…

Tailwind CSS 自定义工具类与主题配置指南

一、自定义工具类配置在 src/tailwind.css 文件中&#xff0c;我们可以通过 layer utilities 指令添加自定义工具类&#xff1a;tailwind base; tailwind components; tailwind utilities;layer utilities {/* 自定义工具 上下浮动效果 */.animate-floatY {animation: floatY 3…

【代码随想录二刷|704.二分查找、27.移除元素、977.有序数组的平方】

704.二分查找 题目链接&#xff1a;704. 二分查找 - 力扣&#xff08;LeetCode&#xff09; class Solution { public:int search(vector<int>& nums, int target) {//不用二分查找&#xff0c;直接求// for(int i0;i<nums.size();i){// if(nums[i]target)…

基于Vue的工业设备大屏可视化模板(含设备地图分布+宣传模块+报表展示+三维模型加载预览)

场景 为实现工业设备可视化大屏需求&#xff0c;可实现基于地图的设备数据管理&#xff0c;点击具体设备可进行详细介绍和三维模型展示。 可播放宣传视频&#xff0c;可展示PM数据报表等数据&#xff0c;可接受报警数据提醒、统计等数据。 基于现有开源平台框架进行二次改造…

堆(Heap)优先级队列(Priority Queue)

一、堆的概念堆&#xff08;Heap&#xff09;是一种特殊的基于树的数据结构&#xff0c;通常分为最大堆和最小堆两种类型。它满足堆属性&#xff1a;对于最大堆&#xff0c;父节点的值总是大于或等于其子节点的值&#xff1b;而对于最小堆&#xff0c;父节点的值总是小于或等于…

踩坑记录:因版本不匹配导致 Boost 1.85 编译失败的完整解决过程

踩坑记录&#xff1a;因版本不匹配导致 Boost 1.85 编译失败的完整解决过程 转载请注明出处&#xff0c;欢迎评论区交流。 背景 最近在 Windows 11 VS2022 环境下尝试用 b2 编译 Boost 1.85.0&#xff0c;结果一路踩坑&#xff0c;最后发现罪魁祸首是 Boost.Build 自带的 msv…

InfluxDB Line Protocol 协议深度剖析(二)

四、Line Protocol 写入操作与实践&#xff08;一&#xff09;HTTP API 写入使用 HTTP API 是通过 Line Protocol 写入数据到 InfluxDB 的常用方式。InfluxDB 1.x&#xff1a;请求方式为 POST&#xff0c;URL 格式为 “http://host:port/write?dbdatabase_name”。其中&#x…

负载均衡:提升业务性能的关键技术

一.负载均衡&#xff08;3.6 &#xff09;1.1.什么是负载均衡&#xff1a;负载均衡&#xff1a;Load Balance&#xff0c;简称LB&#xff0c;是一种服务或基于硬件设备等实现的高可用反向代理技术&#xff0c;负载均 衡将特定的业务(web服务、网络流量等)分担给指定的一个或多个…

【STM32项目】智能家居(版本1)

✌️✌️大家好&#xff0c;这里是5132单片机毕设设计项目分享&#xff0c;今天给大家分享的是基于《基于STM32的智能家居设计》。 目录 1、系统功能 2.1、硬件清单 2.2、功能介绍 2.3、控制模式 2、演示视频和实物 3、系统设计框图 4、软件设计流程图 5、原理图 6、主…

OpenSCA开源社区每日安全漏洞及投毒情报资讯—2025年7月24日

2025年7月24日安全风险情报资讯在野漏洞风险&#xff08;CVE未收录&#xff09;&#xff1a;1公开漏洞精选&#xff1a;2组件投毒情报&#xff1a;2在野漏洞风险&#xff08;CVE未收录&#xff09;1.1 gemini-cli项目潜在命令注入漏洞项目详情项目描述&#xff1a;gemini-cli是…

飞算 JavaAI 深度实战:从老项目重构到全栈开发的降本增效密码

飞算 JavaAI 深度实战&#xff1a;从老项目重构到全栈开发的降本增效密码引言正文一、智能引导模块&#xff1a;老项目重构的 “手术刀” 级解决方案1.1 本地化智能分析&#xff1a;IDEA 插件实操演示1.1.1 &#x1f4cc; IDEA 插件安装步骤1.1.1.1 首先打开idea工具&#xff0…

分布式推客系统开发全解:微服务拆分、佣金结算与风控设计

一、推客系统概述与市场背景推客系统&#xff08;也称为分销系统或社交电商系统&#xff09;已成为现代电商平台和内容平台的重要增长引擎。根据最新统计数据&#xff0c;2023年社交电商市场规模已突破3万亿元&#xff0c;占整体电商市场份额的25%以上。推客系统的核心价值在于…

Linux tcpdump 抓取udp 报文

一、tcpdump 支持命令选项tcpdump -i # 指定监听网络接口tcpdump -w # 将捕获到的信息保存到文件中&#xff0c;且不分析和打印在屏幕tcpdump -r # 从文件中读取数据tcpdump -n # 不把 ip 转化成域名tcpdump -t # 在每行的输出中不显示时间tcpdump -v # 产生详细的输出tc…

Oracle数据块8KB、OS默认认块管理4KB,是否需调整大小为一致?

上班路上&#xff0c;脑中忽然闪现一个问题&#xff1a;Oracle数据库块大小&#xff08;8KB&#xff09;、操作系统文件系统块大小&#xff08;4KB&#xff09;&#xff0c;为了减少IOPS&#xff0c;需不需要调整为一致&#xff1f;在数据块保持一致的情况下&#xff0c;针对频…

卡尔曼滤波器噪声方差设置对性能影响的仿真研究

卡尔曼滤波器噪声方差设置对性能影响的仿真研究 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家,觉得好请收藏。点击跳转到网站。 1. 引言 卡尔曼滤波器是一种广泛应用于信号处理、控制系统、导航系统等领域的递归估计算法。它通过对系…

“多线程修路:当count++变成灾难现场”

1.现象 当我们操作一个线程池的时候&#xff0c;可能需要去计数&#xff0c;也就是统计count&#xff0c;那我们这里有一个疑问&#xff0c;会不会产生线程安全问题&#xff1f; 毫无疑问绝对会有线程安全问题。在线程池环境中&#xff0c;多个线程并发访问和修改一个共享的 co…

GaussDB null的用法

1 null的定义null 空值代表丢失的未知数据。 默认情况下&#xff0c;表列可以保存 null 值。 本章解释 is null 和 is not null 操作符。2 null值的赘述如果表中的列是可选的&#xff0c;那么我们可以插入一个新记录或更新一个现有记录&#xff0c;而无 需向列添加一个值。这意…