分享react+three.js展示温湿度采集终端

前言

气象站将采集到的相关气象数据通过GPRS/3G/4G无线网络发送到气象站监测中心,摆脱了地理空间的限制。

前端:气象站主机将采集好的气象数据存储到本地,通过RS485等线路与GPRS/3G/4G无线设备相连。

通信:GPRS/3G/4G无线设备通过互联网与物联网云平台相连,气象站有计划的将收集到的气象信息通过无线设备发送到监控数据中心。

后台:气象监控中心通过互联网实现了对前端所有的自动气象站数据的采集和整合。

1、摆脱了地理空间的限制,可以在有无线信号的任何地方架设自动气象站点。

2、高规格工业级无线通信设备,有力的保证了气象数据的稳定可靠。

3、体积小巧、安装方便,使得现场安装调试人员轻松高效。

4、费用低廉,降低了运用成本。

温度、湿度等环境数据整合,趋势模拟。

温湿度采集终端

Pt100 就是说它的阻值在 0 度时为 100 欧姆, PT100 温度传感器。是一种以铂(Pt) 作成的电阻式温度传感器,属于正电阻系数, 其电阻和温度变化的关系式如下: R=Ro(1+α T)。广泛应用于实验室及工业环境。

技术参数

       存储温度:-10 ~ +55 °C、湿度 0~85%RH

       测量精度:温度: ±0.5°C ~ ±0.7°C

       显示分辨率: 0.1 C

       记录时间间隔:2秒~24小时

       存储:数据存储量 65000组数据

       电池电量:电池类型 1颗 2600mA 18650锂电池 

       电池寿命:3 年(测量速率在10秒/刷新 300秒/记录)

       尺寸:135mm×125mm×36mm

       材料/外壳: ABS工程塑料

PLC版

web简版

react+three.js,无三维建模软件,web三维展现温湿度采集器

应用程序的模块化理念,使用模块来构建你的代码。通过将实现隐藏在一个简单的接口后面,您可以使您的应用程序万无一失且易于使用。它只做它应该做的,没有别的 通过隐藏实现,我们对使用我们代码的人实施了良好的编码风格。您可以访问的实现越多,它就越有可能成为您以后必须处理的复杂的半生不熟的“修复”。创建3D场景时,唯一的限制是您的想象力 - 以及您的技术知识深度。要点是如何描述3D空间的坐标系和用于在坐标系内移动对象。场景图是一种用于描述构成我们场景的对象层次结构的结构,向量是用于描述3D空间中的位置(以及许多其他事物) ,还有不少于两种描述旋转的方式:欧拉角Euler angles和四元数quaternions

依赖

"react": "^18.2.0",

"three": "^0.162.0",

app.tsx

import React, { useEffect, useRef, useState } from 'react'
import './App.css';
import { World } from './World/World.js';interface appProps {style?: Record<string, unknown>;[key: string]: unknown;
}function App(props: appProps) {const { style, ...pros} = props;const renderRef = useRef(null);let  world: World;useEffect(() => {// eslint-disable-next-line @typescript-eslint/strict-boolean-expressionsif (renderRef && renderRef.current) {// Get a reference to the container element//const container = document.querySelector('#scene-container');//const container = document.getElementById('scene-container')// 1. Create an instance of the World app//world = new World(container);world = new World(renderRef.current);// 2. Render the scene// start the animation loopworld.start();}const timer = setInterval(() => {if(isAutoRotate){world.start();world.tick();}else{world.stop();}}, 1);return () => {cancelAnimationFrame(1);clearInterval(timer);};}, [renderRef])return (<div className="App"><header className="header"></header><main><div id="scene-container" ref={renderRef} style={{ position: 'relative', width: '100%', height: 'calc( 100vh - 100px )', ...style }} {...pros}></div></main><footer style={ { background: 'skyblue', height: '30px' }}></footer></div>)
}export default App;

world.js

/* eslint-disable no-undef */
/* eslint-disable @typescript-eslint/strict-boolean-expressions */
/** @Date: 2024-03-21 14:57:52* @LastEditors: david* @LastEditTime: 2024-03-21 17:04:01* @FilePath: .\src\components\World.js* @Description: 创建三维场景单例*/
import { createCamera } from '../components/camera.js';
import { createCube } from '../components/cube.js';
import { createScene } from '../components/scene.js';
import { createControls } from '../components/controls.js';
import { createLights } from '../components/lights.js';import { createRenderer } from '../systems/renderer.js';
import { Resizer } from '../systems/Resizer.js';
import { Loop } from '../systems/Loop.js';// These variables are module-scoped: we cannot access them
// from outside the module 将相机、渲染器和场景创建为模块作用域变量
let camera;
//let scene;
let light;
let renderer;
let controls;
let loop;
// 温湿度采集器
import { changeMaterial, updateData } from '../components/canvasTexture.js'/*** @description: 初始化三维场景 容器* @param {string} container - 三维场景挂载的div容器* @return {*}*/
class World {// 1. Create an instance of the World appconstructor(container) {// 首次使用构造器实例if (!(World.instance instanceof World)) {// 初始化相机camera = createCamera();// 初始化场景model.scene = createScene();// 初始化灯光light = createLights({directionX: 30,directionY: 10,directionZ: 0.5});model.scene.add(...light);// 初始化渲染器renderer = createRenderer();renderer.setSize(container.clientWidth, container.clientHeight);// Type: Element | Stringcontainer.appendChild(renderer.domElement);// container.innerHTML = null;loop = new Loop(camera, model.scene, renderer);// 初始化控制器controls = createControls(camera,renderer)//loop.updatables.push(controls);// 添加模型const cube = createCube();model.scene.add(cube);const  collectorCube = changeMaterial();// async await Promise resole reject Promise.all 解决异步加载模型和贴图collectorCube.then((res) => {model.scene.add(res);//loop.updatables.push(res);}).catch(err => {console.log('温湿度采集器添加失败:'+err)})// stop the cube's animationloop.updatables.push(cube);controls.addEventListener('change', () => {this.render();});const resizer = new Resizer(container, camera, renderer);resizer.onResize = () => {this.render();};this.render();this.animate();// 将this挂载到World这个类的instance属性上World.instance = this}return World.instance}// 2. Render the scenerender() {// draw a single frameif ((Boolean(renderer)) && (Boolean(model.scene)) && (Boolean(camera))) {renderer.render(model.scene, camera);}}animate(){try{// eslint-disable-next-line no-undef//requestAnimationFrame(this.animate);requestAnimationFrame(this.animate.bind(this));TWEEN.update();//更新控制器this.render()} catch (error) {// eslint-disable-next-line @typescript-eslint/strict-boolean-expressionsconsole.log(`Failed to add world imagery: ${error}`);}// eslint-disable-next-line @typescript-eslint/strict-boolean-expressionsif (controls) {controls.update();}}
}export { World };

camera.js

import { PerspectiveCamera, MathUtils } from 'three';function createCamera() {const camera = new PerspectiveCamera(45, // fov = Field Of View1, // aspect ratio (dummy value)0.1, // near clipping plane10000, // far clipping plane);// move the camera back so we can view the scene// camera.position.set(0, 0, 30);const layoutWidth = 25;const angle = camera.fov / 2;  // 夹角const rad = MathUtils.degToRad(angle);  // 转为弧度值const cameraZ = layoutWidth / 2 / Math.tan(rad);// 调整相机的 Z 轴位置,使桌台元素完整显示到场景camera.position.set(0, 15, cameraZ);return camera;
}export { createCamera };

scene.js

import { Color, Scene, Fog } from 'three';function createScene() {const scene = new Scene();scene.background = new Color(0xe6f4ff);scene.fog = new Fog( 0xa0a0a0, 5, 250 );return scene;
}export { createScene };

controls.js

import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
function createControls ( Camera, renderer ) {// 轨道控制器const controls  = new OrbitControls(Camera, renderer.domElement);//设置控制器的中心点controls.target.set(0, 10, 0);const distanceZ = Camera.position.z;// 如果使用animate方法时,将此函数删除//controls.addEventListener( 'change', render );// 使动画循环使用时阻尼或自转 意思是否有惯性controls.enableDamping = false;//动态阻尼系数 就是鼠标拖拽旋转灵敏度// 阻尼系数controls.dampingFactor = 0.1;controls.minPolarAngle = Math.PI / 12;controls.maxPolarAngle = (Math.PI * 19) / 40;//是否可以缩放controls.enableZoom = true;//是否自动旋转controls.autoRotate = true;controls.autoRotateSpeed = 0.5;//设置相机距离原点的最远距离//controls.minDistance = 10;//设置相机距离原点的最远距离//controls.maxDistance = 200;controls.minDistance = distanceZ / 10;  // 相机离目标点的最小距离(放大)controls.maxDistance = distanceZ * 10;  // 相机离目标点的最大距离(缩小)//是否开启右键拖拽controls.enablePan = true;controls.tick = () => controls.update();return controls;
}export { createControls };

lights.js

import { HemisphereLight, AmbientLight, DirectionalLight, DirectionalLightHelper, SpotLight, SpotLightHelper } from 'three';function createLights({ directionX, directionY, directionZ }) {const hemisphere = new HemisphereLight(0xffffff, 0xffffff, 0.6);// move the light right, up, and towards ushemisphere.position.set(10, 10, 10);const ambient = new AmbientLight(0xffffff, 1);  // 环境光const spot = new SpotLight(0xfdf4d5);spot.position.set(5, directionY * 4, 0);spot.angle = Math.PI / 2;spot.power = 2000;// eslint-disable-next-line @typescript-eslint/no-unused-varsconst spotLightHelper = new SpotLightHelper(spot, 0x00f);const direct = new DirectionalLight(0xffffff, 3);  // 平行光direct.position.set(-directionX / 3, directionY * 4, directionZ * 1.5);direct.castShadow = true;direct.shadow.camera.left = -directionX;direct.shadow.camera.right = directionX;direct.shadow.camera.top = directionZ;direct.shadow.camera.bottom = -directionZ;// eslint-disable-next-line @typescript-eslint/no-unused-varsconst directLightHelper = new DirectionalLightHelper(direct, 1, 0xf00);return [hemisphere, ambient, spot, direct];}export { createLights };

cube.js

import { BoxGeometry, Mesh, //MeshBasicMaterial, MeshStandardMaterial, MathUtils  } from 'three';
function createCube() {// create a geometryconst geometry = new BoxGeometry(1, 1, 1);// create a default (white) Basic material// const material = new MeshBasicMaterial();// Switch the old "basic" material to// a physically correct "standard" materialconst spec = {color: 'purple',}const material = new MeshStandardMaterial(spec);// create a Mesh containing the geometry and materialconst cube = new Mesh(geometry, material);cube.position.set(0, 10, 0);// cube.rotation.set(-0.5, -0.1, 0.8);const radiansPerSecond = MathUtils.degToRad(30);// this method will be called once per framecube.tick = (delta) => {// increase the cube's rotation each framecube.rotation.z += radiansPerSecond * delta;cube.rotation.x += radiansPerSecond * delta;cube.rotation.y += radiansPerSecond * delta;};return cube;
}export { createCube };

loop.js

import { Clock } from "three";
const clock = new Clock();class Loop {constructor(camera, scene, renderer) {this.camera = camera;this.scene = scene;this.renderer = renderer;// somewhere in the Loop class:this.updatables = []}start() {this.renderer.setAnimationLoop(() => {// tell every animated object to tick forward one frame// this.tick();// render a framethis.renderer.render(this.scene, this.camera);});}stop() {this.renderer.setAnimationLoop(null);}tick(){// only call the getDelta function once per frame!const delta = clock.getDelta();// console.log(//   `The last frame rendered in ${delta * 1000} milliseconds`,// );// eslint-disable-next-line @typescript-eslint/strict-boolean-expressionsif(this.updatables.length){for (const object of this.updatables) {if(typeof object.tick == 'function'){object.tick(delta);}}}}
}export { Loop };

renderer.js

import { WebGLRenderer, PCFSoftShadowMap } from 'three';function createRenderer() {const renderer = new WebGLRenderer({ alpha: true, // 透明度antialias: true // 开启抗锯齿});// turn on the physically correct lighting modelrenderer.physicallyCorrectLights = true;renderer.shadowMap.enabled = true;renderer.shadowMap.type = PCFSoftShadowMap;renderer.setClearColor('#f8f8f6', 1);// eslint-disable-next-line no-undefrenderer.setPixelRatio(window.devicePixelRatio);return renderer;
}export { createRenderer };

resizer.js

const setSize = (container, camera, renderer) => {// Set the camera's aspect ratiocamera.aspect = container.clientWidth / container.clientHeight;// update the camera's frustumcamera.updateProjectionMatrix();// update the size of the renderer AND the canvasrenderer.setSize(container.clientWidth, container.clientHeight);// set the pixel ratio (for mobile devices)// eslint-disable-next-line no-undefrenderer.setPixelRatio(window.devicePixelRatio);
};class Resizer {constructor(container, camera, renderer) {// set initial size on loadsetSize(container, camera, renderer);// eslint-disable-next-line no-undefwindow.addEventListener("resize", () => {// set the size again if a resize occurssetSize(container, camera, renderer);// perform any custom actionsthis.onResize();});}// 空方法, 我们可以从Resizer类的外部自定义。// eslint-disable-next-line @typescript-eslint/no-empty-functiononResize() {}}export { Resizer };

canvasTexture.js

/* eslint-disable no-undef */
/* eslint-disable @typescript-eslint/strict-boolean-expressions */
import { CanvasTexture, MeshLambertMaterial, BoxGeometry, Mesh,    } from 'three';
import moment from 'moment';
import collectorImg from '../assets/images/collector.png';
const meshcolor = 0xa1a5a9;
let cube;
let timeNow = new Date().valueOf();
let time = { hum: 40.0, tep: 20.0 };// 方法二:放大画布之后,需要把每一个绘制的 api 都乘以 dpr
// * 这样一来使用的时候就会很麻烦,所以我们需要把所有的绘制操作进行统一封装
// 可以参考这个库:https://github.com/jondavidjohn/hidpi-canvas-polyfill,不过这个库也不是所有 api 都覆盖
const adaptDPR = (canvas)=> { // 在初始化 canvas 的时候就要调用该方法const context = canvas.getContext('2d');const devicePixelRatio = window.devicePixelRatio || 1;const backingStoreRatio = context.webkitBackingStorePixelRatio ||context.mozBackingStorePixelRatio ||context.msBackingStorePixelRatio ||context.oBackingStorePixelRatio ||context.backingStorePixelRatio || 1;const ratiodpr = devicePixelRatio / backingStoreRatio;const { width, height } = canvas;// 重新设置 canvas 自身宽高大小和 css 大小。放大 canvas;css 保持不变,因为我们需要那么多的点// upscale the canvas if the two ratios don't matchif (devicePixelRatio !== backingStoreRatio) {canvas.width = width * ratiodpr;canvas.height = height * ratiodpr;canvas.style.width = width + 'px';canvas.style.height = height + 'px';// 注意这里没有用 scale// now scale the context to counter// the fact that we've manually scaled// our canvas element 通过backing store的像素比例和设备像素比(dpr)来控制你的图片和canvas是保证图片质量和清晰的保证。context.scale(ratiodpr, ratiodpr);}
}
// 每个涉及绘制的 api 时都乘以 dpr
// 获取带数据的canvas
const getTextCanvas = async ({ tep, hum }) => {const time = moment().format('HH:mm:ss');const width = 310, height = 173;const canvas = document.createElement('canvas');canvas.width = width;canvas.height = height;adaptDPR(canvas);const ctx = canvas.getContext('2d');return new Promise((resole) => {if (ctx) {const img = new Image();img.src = collectorImg;//图片加载完后,将其显示在canvas中img.onload = () => {ctx.drawImage(img, 0, 0, width, height);ctx.font = 18 + 'px " bold';ctx.fillStyle = '#333';ctx.textAlign = 'center';ctx.textBaseline = 'middle';// 实时温度ctx.fillText(tep, width * 0.33, height * 0.44);// 实时湿度ctx.fillText(hum, width * 0.33, height * 0.70);// 数据采集时间ctx.font = 10 + 'px " bold';ctx.fillText(time, width * 0.24 , height * 0.245);resole(canvas);};}});
}// 改变材质种类
const changeMaterial = async () => {const canvas = await getTextCanvas({ hum: 40, tep: 20 });if (canvas) {const texture = new CanvasTexture(canvas);const materials = [new MeshLambertMaterial({ color: meshcolor, opacity: 1, transparent: true }),new MeshLambertMaterial({ color: meshcolor, opacity: 1, transparent: true }),new MeshLambertMaterial({ color: meshcolor, opacity: 1, transparent: true }),new MeshLambertMaterial({ color: meshcolor, opacity: 1, transparent: true }),new MeshLambertMaterial({color: meshcolor,opacity: 1,transparent: true,map: texture,}),new MeshLambertMaterial({ color: meshcolor, opacity: 1, transparent: true }),];const geometry = new BoxGeometry(8.404, 6.16, 1);cube = new Mesh(geometry, materials);cube.position.set(0, 15, 0);//scene.add(cube);return cube;}
}const updateData = async () => {if (new Date().valueOf() - timeNow > 500) {timeNow = new Date().valueOf();changeValues();}const canvas = await getTextCanvas(time);if (canvas && cube) {cube.material[4].map = new CanvasTexture(canvas);cube.material.map.needsUpdate = true;}
}// 更新time数据
const changeValues = () => {const hum = parseFloat((39 + Math.random() * 10).toFixed(1));const tep = parseFloat((19 + Math.random() * 5).toFixed(1));setTime({ hum: hum, tep: tep})
}const setTime = (date)=>{time = date
}export {changeMaterial,updateData
}

采集器正面贴图,空出需要动态渲染的时间、温度、湿度,采集器用用最简单的长方形盒子代替。

index.tsx

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement
);root.render(<React.StrictMode><App /></React.StrictMode>
);

index.html

<!DOCTYPE html>
<html lang="zh-CN"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><meta name="theme-color" content="#000000" /><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="renderer" content="webkit"><meta name="force-rendering" content="webkit"><meta name="google-site-verification" content="FTeR0c8arOPKh8c5DYh_9uu98_zJbaWw53J-Sch9MTg"><meta data-rh="true" name="keywords" content="React three.js World示例"><meta data-rh="true" name="description" content="React three.js World示例"><meta data-rh="true" property="og:title" content="React three.js World示例"><link rel="icon" href="./favicon.ico"><title>React three.js World示例</title></head><body><div id="root"></div></body>
</html>

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

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

相关文章

真北3月小结:15小时黄金定律

我以前是敏捷爱好者&#xff0c;现在是跑步爱好者&#xff0c;希望将来能成为赚钱爱好者。我们跑步&#xff0c;我们读书&#xff0c;我们写作&#xff0c;都是为了获得#高配人生。15小时黄金定律是指&#xff1a;每月跑步15小时、每月读书15小时、每月写作15小时。 1、跑步 跑…

系统架构图怎么画

画架构图是架构师的一门必修功课。 对于架构图是什么这个问题&#xff0c;我们可以按以下等式进行概括&#xff1a; 架构图 架构的表达 架构在不同抽象角度和不同抽象层次的表达&#xff0c;这是一个自然而然的过程。 不是先有图再有业务流程、系统设计和领域模型等&#…

【C语言】预处理常见知识详解(宏详解)

文章目录 1、预定义符号2、define2.1 define 定义常量2.2 define 定义宏 3、#和##3.1 **#**3.2 **##** 4、条件编译&#xff08;开关&#xff09; 1、预定义符号 在C语言中内置了一些预定义符号&#xff0c;可以直接使用&#xff0c;这些符号实在预处理期间处理的&#xff0c;…

ssm网上订餐管理系统开发mysql数据库web结构java编程计算机网页源码eclipse项目采用线性算法

一、源码特点 ssm 网上订餐管理系统是一套完善的信息系统&#xff0c;结合springMVC框架完成本系统&#xff0c;对理解JSP java编程开发语言有帮助系统采用SSM框架&#xff08;MVC模式开发&#xff09;&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模…

【计算机网络】第 9 问:四种信道划分介质访问控制?

目录 正文什么是信道划分介质访问控制&#xff1f;什么是多路复用技术&#xff1f;四种信道划分介质访问控制1. 频分多路复用 FDM2. 时分多路复用 TDM3. 波分多路复用 WDM4. 码分多路复用 CDM 正文 什么是信道划分介质访问控制&#xff1f; 信道划分介质访问控制&#xff08;…

主流公链 - Filecoin

探索Filecoin&#xff1a;去中心化存储网络 1. Filecoin简介 Filecoin是一个去中心化的存储网络&#xff0c;旨在通过区块链技术实现全球性的分布式文件存储和检索市场。Filecoin允许用户将文件存储在网络中的节点上&#xff0c;并通过加密、分片和复制等技术保证数据的安全性…

OpenHarmony开发之WebGL开发指导与介绍

WebGL的全称为Web Graphic Library(网页图形库)&#xff0c;主要用于交互式渲染2D图形和3D图形。目前OpenHarmony中使用的WebGL是基于OpenGL裁剪的OpenGL ES&#xff0c;可以在HTML5的canvas元素对象中使用&#xff0c;无需使用插件&#xff0c;支持跨平台。WebGL程序是由JavaS…

hadoop-3.1.1分布式搭建与常用命令

一、准备工作 1.首先需要三台虚拟机&#xff1a; master 、 node1 、 node2 2.时间同步 ntpdate ntp.aliyun.com 3.调整时区 cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime 4.jdk1.8 java -version 5.修改主机名 三台分别执行 vim /etc/hostname 并将内容指定为…

Mysql数据库-DQL查询

Mysql数据库-DQL基本查询 1 DQL基本查询1.1 基础查询1.2 WHERE子句1&#xff09;算术运算符2&#xff09;逻辑运算符3&#xff09;比较运算符A&#xff09;BETWEEN... AND ...B&#xff09;IN(列表)C&#xff09;NULL值判断 4&#xff09;综合练习 2 DQL高级查询2.1 LIKE 模糊查…

2024年北京事业单位报名照片要求,注意格式

2024年北京事业单位报名照片要求&#xff0c;注意格式

HarmonyOS 应用开发之ExtensionAbility组件

ExtensionAbility组件是基于特定场景&#xff08;例如服务卡片、输入法等&#xff09;提供的应用组件&#xff0c;以便满足更多的使用场景。 每一个具体场景对应一个 ExtensionAbilityType&#xff0c;开发者只能使用&#xff08;包括实现和访问&#xff09;系统已定义的类型。…

金属氧化物压敏电阻的冲击破坏机理高能压敏电阻分析

以氧化锌为主的金属氧化物阀片在一定的电压和电流作用下的破坏可分为热破坏和冲击破坏两类。 热破坏是指氧化锌电阻在交流电压持续作用时发生的破坏,即由于阀片在交流作用下的发热超过了其散热能力而导致的热平衡失控的现象。交流引起的热破坏可以分为几种不同情况:一种是由于…

【Redis教程0x08】详解Redis过期删除策略内存淘汰策略

引言 Redis的过期删除策略和内存淘汰策略是经常被问道的问题&#xff0c;这两个机制都是做删除操作&#xff0c;但是触发的条件和使用的策略是不同的。今天就来深入理解一下这两个策略。 过期删除策略 Redis 是可以对 key 设置过期时间的&#xff0c;因此需要有相应的机制将…

[flink 实时流基础系列]揭开flink的什么面纱基础一

Apache Flink 是一个框架和分布式处理引擎&#xff0c;用于在无边界和有边界数据流上进行有状态的计算。Flink 能在所有常见集群环境中运行&#xff0c;并能以内存速度和任意规模进行计算。 文章目录 0. 处理无界和有界数据无界流有界流 1. Flink程序和数据流图2. 为什么一定要…

JMM Java内存模型

JMM本身是一个抽象的概念,不是真实存在的,它仅仅是一种规定或者说是规范 1.用来实现线程和主内存直接的抽象关系 2.屏蔽各个硬件平台和操作系统的内存访问差异,使得java程序在各种平台都能达到一致的内存访问效果 JMM的三大特性 可见性 多线程环境下,某个线程修改了变量…

构建智能未来:探索AI人工智能产品业务架构的创新之路

随着人工智能技术的快速发展&#xff0c;AI人工智能产品在各行各业中扮演着越来越重要的角色。本文将深入探讨AI人工智能产品业务架构的创新之路&#xff0c;探讨如何构建智能未来的商业生态。 ### AI人工智能产品业务架构的重要性 AI人工智能产品的业务架构是支撑产品成功的…

RTSP应用:实现视频流的实时推送

在实现实时视频流推送的项目中&#xff0c;RTSP&#xff08;Real Time Streaming Protocol&#xff09;协议扮演着核心角色。本文将指导你通过安装FFmpeg软件&#xff0c;下载并编译live555&#xff0c;以及配置ffmpeg进行视频流推送&#xff0c;来实现一个基本的RTSP流媒体服务…

element-ui 自定义点击图标/文本/按钮触发el-date-picker时间组件,不使用插槽

天梦星服务平台 (tmxkj.top)https://tmxkj.top/#/ 1. 图片预览 2.上代码 2.1html <el-button class"hide_input" size"small"><svg t"1711608996149" class"icon" viewBox"0 0 1024 1024" version"1.1"…

Haproxy2.8.1+Lua5.1.4部署,haproxy.cfg配置文件详解和演示

目录 一.快速安装lua和haproxy 二.配置haproxy的配置文件 三.配置haproxy的全局日志 四.测试负载均衡、监控和日志效果 五.server常用可选项 1.check 2.weight 3.backup 4.disabled 5.redirect prefix和redir 6.maxconn 六.调度算法 1.静态 2.动态 一.快速安装lu…

【Redis】Redis 内存管理,Redis事务,bigkey和hotkey

目录 Redis 内存管理 缓存数据设置过期时间&#xff1f; Redis 是如何判断数据是否过期的呢&#xff1f; 过期删除策略 内存淘汰机制 主从模式下对过期键的处理&#xff1f; LRU和LFU的区别 Redis事务 定义和原理 Redis 事务的注意点&#xff1f; 为什么不支持回滚&a…