当前位置: 首页 > news >正文

后端要一次性返回我10万条数据

问题描述

  • 面试官:后端一次性返回10万条数据给你,你如何处理?
  • 我:歪嘴一笑,what the f**k!

问题考察点

看似无厘头的问题,实际上考查候选人知识的广度和深度,虽然在工作中这种情况很少遇到...

  • 考察前端如何处理大量数据
  • 考察候选人对于大量数据的性能优化
  • 考察候选人处理问题的思考方式(关于这一点,文末会说到,大家继续阅读)
  • ......

文末会提供完整代码,供大家更好的理解

使用express创建一个十万条数据的接口

若是道友对express相关不太熟悉的话,有空可以看看笔者的这一篇全栈文章(还有完整代码哦):《Vue+Express+Mysql全栈项目之增删改查、分页排序导出表格功能》

route.get("/bigData", (req, res) => {res.header('Access-Control-Allow-Origin', '*'); // 允许跨域let arr = [] // 定义数组,存放十万条数据for (let i = 0; i < 100000; i++) { // 循环添加十万条数据arr.push({id: i + 1,name: '名字' + (i + 1),value: i + 1,})}res.send({ code: 0, msg: '成功', data: arr }) // 将十万条数据返回之
})
复制代码

点击按钮,发请求,获取数据,渲染到表格上

html结构如下:

<el-button :loading="loading" @click="plan">点击请求加载</el-button><el-table :data="arr"><el-table-column type="index" label="序" /><el-table-column prop="id" label="ID" /><el-table-column prop="name" label="名字" /><el-table-column prop="value" label="对应值" />
</el-table>data() {return {arr: [],loading: false,};
},async plan() {// 发请求,拿数据,赋值给arr
}
复制代码

方案一 直接渲染所有数据

如果请求到10万条数据直接渲染,页面会卡死的,很显然,这种方式是不可取的

 async plan() {this.loading = true;const res = await axios.get("http://ashuai.work:10000/bigData");this.arr = res.data.data;this.loading = false;
}
复制代码

方案二 使用定时器分组分批分堆依次渲染(定时加载、分堆思想)

  • 正常来说,十万条数据请求,需要2秒到10秒之间(有可能更长,取决于数据具体内容)
  • 而这种方式就是,前端请求到10万条数据以后,先不着急渲染,先将10万条数据分堆分批次
  • 比如一堆存放10条数据,那么十万条数据就有一万堆
  • 使用定时器,一次渲染一堆,渲染一万次即可
  • 这样做的话,页面就不会卡死了

用户所看到的效果图是如下

效果图

分组分批分堆函数

  • 我们先写一个函数,用于将10万条数据进行分堆
  • 所谓的分堆其实思想就是一次截取一定长度的数据
  • 比如一次截取10条数据,头一次截取0~9,第二次截取10~19等固定长度的截取
  • 举例原来的数据是:[1,2,3,4,5,6,7]
  • 假设我们分堆以后,一堆分3个,那么得到的结果就是二维数组了
  • 即:[ [1,2,3], [4,5,6], [7]]
  • 然后就遍历这个二维数组,得到每一项的数据,即为每一堆的数据
  • 进而使用定时器一点点、一堆堆赋值渲染即可

分组分批分堆函数(一堆分10个)

function averageFn(arr) {let i = 0; // 1. 从第0个开始截取let result = []; // 2. 定义结果,结果是二维数组while (i < arr.length) { // 6. 当索引等于或者大于总长度时,即截取完毕// 3. 从原始数组的第一项开始遍历result.push(arr.slice(i, i + 10)); // 4. 在原有十万条数据上,一次截取10个用于分堆i = i + 10; // 5. 这10条数据截取完,再截取下十条数据,以此类推}return result; // 7. 最后把结果丢出去即可
}
复制代码

创建定时器去依次赋值渲染

比如我们每隔一秒钟去赋值渲染一次

  async plan() {this.loading = true;const res = await axios.get("http://ashuai.work:10000/bigData");this.loading = false;let twoDArr = averageFn(res.data.data);for (let i = 0; i < twoDArr.length; i++) {// 相当于在很短的时间内创建许多个定时任务去处理setTimeout(() => {this.arr = [...this.arr, ...twoDArr[i]]; // 赋值渲染}, 1000 * i); // 17 * i // 注意设定的时间间隔... 17 = 1000 / 60}},
复制代码

这种方式,相当于在很短的时间内创建许多个定时任务去处理,定时任务太多了,也耗费资源啊。

实际上,这种方式就有了大数据量分页的思想

方案三 使用requestAnimationFrame替代定时器去做渲染

关于requestAnimationFrame定时器优点,道友们可以看笔者的这篇文章:《性能优化之通俗易懂学习requestAnimationFrame和使用场景举例》

反正大家遇到定时器的时候,就可以考虑一下,是否可以使用请求动画帧进行优化执行渲染?

如果使用请求动画帧的话,就要修改一下代码写法了,前面的不变化,plan方法中的写法变一下即可,注意注释:

async plan() {this.loading = true;const res = await axios.get("http://ashuai.work:10000/bigData");this.loading = false;// 1. 将大数据量分堆let twoDArr = averageFn(res.data.data);// 2. 定义一个函数,专门用来做赋值渲染(使用二维数组中的每一项)const use2DArrItem = (page) => {// 4. 从第一项,取到最后一项if (page > twoDArr.length - 1) {console.log("每一项都获取完了");return;}// 5. 使用请求动画帧的方式requestAnimationFrame(() => {// 6. 取出一项,就拼接一项(concat也行)this.arr = [...this.arr, ...twoDArr[page]];// 7. 这一项搞定,继续下一项page = page + 1;// 8. 直至完毕(递归调用,注意结束条件)use2DArrItem(page);});};// 3. 从二维数组中的第一项,第一堆开始获取并渲染(数组的第一项即索引为0)use2DArrItem(0); 
},
复制代码

方案四 搭配分页组件,前端进行分页(每页展示一堆,分堆思想)

这种方式,笔者曾经遇到过,当时的对应场景是数据量也就几十条,后端直接把几十条数据丢给前端,让前端去分页

后端不做分页的原因是。他当时临时有事情请假了,所以就前端去做分页了。

  • 数据量大的情况下,这种方式,也是一种解决方案
  • 思路也是在所有数据的基础上进行截取
  • 简要代码如下:
getShowTableData() { // 获取截取开始索引 let begin = (this.pageIndex - 1) * this.pageSize; // 获取截取结束索引let end = this.pageIndex * this.pageSize; // 通过索引去截取,从而展示this.showTableData = this.allTableData.slice(begin, end); 
}
复制代码

完整案例代码,请看笔者的这篇文章:《后端一次性返回所有的数据,让前端截取展示做分页》

实际上,这种大任务拆分成许多小任务,这种方式,做法,应用的思想就是分片的方式(时间),在别的场景,比如大文件上传的时候,也有这种思想,比如一个500MB的大文件,拆分成50个小文件,一个是10MB这样...至于大文件上传的文章,那就等笔者有空了再写呗...

方案五 表格滚动触底加载(滚动到底,再加载一堆)

这里重点就是我们需要去判断,何时滚动条触底。判断方式主要有两种

  • scrollTop + clientHeight >= innerHeight
  • new MutationObserver()去观测

目前市面上主流的一些插件的原理,大致是这两种。

笔者举例的这是,是使用的插件v-el-table-infinite-scroll,本质上这个插件是一个自定义指令。对应npm地址:www.npmjs.com/package/el-…

当然也有别的插件,如vue-scroller 等:一个意思,不赘述

注意,触底加载也是要分堆的,将发请求获取到的十万条数据,进行分好堆,然后每触底一次,就加载一堆即可

在el-table中使用el-table-infinite-scroll指令步骤

安装,注意版本号(区分vue2和vue3)

cnpm install --save el-table-infinite-scroll@1.0.10

注册使用指令插件

// 使用无限滚动插件
import elTableInfiniteScroll from 'el-table-infinite-scroll';
Vue.use(elTableInfiniteScroll);
复制代码

因为是一个自定义指令,所以直接写在el-table标签上即可

<el-tablev-el-table-infinite-scroll="load":data="tableData"
><el-table-column prop="id" label="ID"></el-table-column><el-table-column prop="name" label="名字"></el-table-column>
</el-table>async load() {// 触底加载,展示数据...
},
复制代码

案例代码

为了方便大家演示,这里笔者直接附上一个案例代码,注意看其中的步骤注释即可

<template><div class="box"><el-tablev-el-table-infinite-scroll="load"height="600":data="tableData"borderstyle="width: 80%"v-loading="loading"element-loading-text="数据量太大啦,客官稍后..."element-loading-spinner="el-icon-loading"element-loading-background="rgba(255, 255, 255, 0.5)":header-cell-style="{height: '24px',lineHeight: '24px',color: '#606266',background: '#F5F5F5',fontWeight: 'bold',}"><el-table-column type="index" label="序"></el-table-column><el-table-column prop="id" label="ID"></el-table-column><el-table-column prop="name" label="名字"></el-table-column><el-table-column prop="value" label="对应值"></el-table-column></el-table></div>
</template><script>
// 分堆函数
function averageFn(arr) {let i = 0;let result = [];while (i < arr.length) {result.push(arr.slice(i, i + 10)); // 一次截取10个用于分堆i = i + 10; // 这10个截取完,再准备截取下10个}return result;
}
import axios from "axios";
export default {data() {return {allTableData: [], // 初始发请求获取所有的数据tableData: [], // 要展示的数据loading: false};},// 第一步,发请求,获取大量数据,并转成二维数组,分堆分组分块存储async created() {this.loading = true;const res = await axios.get("http://ashuai.work:10000/bigData");this.allTableData = averageFn(res.data.data); // 使用分堆函数,存放二维数组// this.originalAllTableData = this.allTableData // 也可以存一份原始值,留作备用,都行的this.loading = false;// 第二步,操作完毕以后,执行触底加载方法this.load(); },methods: {// 初始会执行一次,当然也可以配置,使其不执行async load() {console.log("自动多次执行之,首次执行会根据高度去计算要执行几次合适");// 第五步,触底加载相当于把二维数组的每一项取出来用,取完用完时return停止即可if (this.allTableData.length == 0) {console.log("没数据啦");return;}// 第三步,加载的时候,把二维数组的第一项取出来,拼接到要展示的表格数据中去let arr = this.allTableData[0];this.tableData = this.tableData.concat(arr);// 第四步,拼接展示以后,再把二维数组的第一项的数据删除即可this.allTableData.shift();},},
};
</script>
复制代码

效果图

方案六 使用无限加载/虚拟列表进行展示

什么是虚拟列表?

  • 所谓的虚拟列表实际上是前端障眼法的一种表现形式。
  • 看到的好像所有的数据都渲染了,实际上只渲染可视区域的部分罢了
  • 有点像我们看电影,我们看的话,是在一块电影屏幕上,一秒一秒的看(不停的放映)
  • 但是实际上电影有俩小时,如果把两个小时的电影都铺开的话,那得需要多少块电影屏幕呢?
  • 同理,如果10万条数据都渲染,那得需要多少dom节点元素呢?
  • 所以我们只给用户看,他当下能看到的
  • 如果用户要快进或快退(下拉滚动条或者上拉滚动条)
  • 再把对应的内容呈现在电影屏幕上(呈现在可视区域内)
  • 这样就实现了看着像是所有的dom元素每一条数据都有渲染的障眼法效果了

关于前端障眼法,在具体工作中,如果能够巧妙使用,会大大提升我们的开发效率的

写一个简单的虚拟列表

效果图

这里笔者直接上代码,大家复制粘贴即可使用,笔者写了一些注释,以便于大家理解。当然也可以去笔者的仓库中去瞅瞅哦,GitHub仓库在文末

代码

<template><!-- 虚拟列表容器,类似“窗口”,窗口的高度取决于一次展示几条数据比如窗口只能看到10条数据,一条40像素,10条400像素故,窗口的高度为400像素,注意要开定位和滚动条 --><divclass="virtualListWrap"ref="virtualListWrap"@scroll="handleScroll":style="{ height: itemHeight * count + 'px' }"><!-- 占位dom元素,其高度为所有的数据的总高度 --><divclass="placeholderDom":style="{ height: allListData.length * itemHeight + 'px' }"></div><!-- 内容区,展示10条数据,注意其定位的top值是变化的 --><div class="contentList" :style="{ top: topVal }"><!-- 每一条(项)数据 --><divv-for="(item, index) in showListData":key="index"class="itemClass":style="{ height: itemHeight + 'px' }">{{ item.name }}</div></div><!-- 加载中部分 --><div class="loadingBox" v-show="loading"><i class="el-icon-loading"></i>&nbsp;&nbsp;<span>loading...</span></div></div>
</template>
<script>
import axios from "axios";
export default {data() {return {allListData: [], // 所有的数据,比如这个数组存放了十万条数据itemHeight: 40, // 每一条(项)的高度,比如40像素count: 10, // 一屏展示几条数据start: 0, // 开始位置的索引end: 10, // 结束位置的索引topVal: 0, // 父元素滚动条滚动,更改子元素对应top定位的值,确保联动loading: false,};},computed: {// 从所有的数据allListData中截取需要展示的数据showListDatashowListData: function () {return this.allListData.slice(this.start, this.end);},},async created() {this.loading = true;const res = await axios.get("http://ashuai.work:10000/bigData");this.allListData = res.data.data;this.loading = false;},methods: {// 滚动这里可以加上节流,减少触发频次handleScroll() {/*** 获取在垂直方向上,滚动条滚动了多少像素距离Element.scrollTop** 滚动的距离除以每一项的高度,即为滚动到了多少项,当然,要取个整数* 例:滚动4米,一步长0.8米,滚动到第几步,4/0.8 = 第5步(取整好计算)** 又因为我们一次要展示10项,所以知道了起始位置项,再加上结束位置项,* 就能得出区间了【起始位置, 起始位置 + size项数】==【起始位置, 结束位置】* */const scrollTop = this.$refs.virtualListWrap.scrollTop;this.start = Math.floor(scrollTop / this.itemHeight);this.end = this.start + this.count;/*** 动态更改定位的top值,确保联动,动态展示相应内容* */this.topVal = this.$refs.virtualListWrap.scrollTop + "px";},},
};
</script>
<style scoped lang="less">
// 虚拟列表容器盒子
.virtualListWrap {box-sizing: border-box;width: 240px;border: solid 1px #000000;// 开启滚动条overflow-y: auto;// 开启相对定位position: relative;.contentList {width: 100%;height: auto;// 搭配使用绝对定位position: absolute;top: 0;left: 0;.itemClass {box-sizing: border-box;width: 100%;height: 40px;line-height: 40px;text-align: center;}// 奇偶行改一个颜色.itemClass:nth-child(even) {background: #c7edcc;}.itemClass:nth-child(odd) {background: pink;}}.loadingBox {position: absolute;top: 0;left: 0;right: 0;bottom: 0;width: 100%;height: 100%;background-color: rgba(255, 255, 255, 0.64);color: green;display: flex;justify-content: center;align-items: center;}
}
</style>
复制代码

使用vxetable插件实现虚拟列表

如果不是列表,是table表格的话,笔者这里推荐一个好用的UI组件,vxetable,看名字就知道做的是表格相关的业务。其中就包括虚拟列表。

vue2vue3版本都支持,性能比较好,官方说:虚拟滚动(最大可以支撑 5w 列、30w 行)

强大!

官方网站地址:vxetable.cn/v3/#/table/…

效果图

效果很丝滑

安装使用代码

注意安装版本,笔者使用的版本如下:

cnpm i xe-utils vxe-table@3.6.11 --save

main.js

// 使用VXETable
import VXETable from 'vxe-table'
import 'vxe-table/lib/style.css'
Vue.use(VXETable)
复制代码

代码方面也很简单,如下:

<template><div class="box"><vxe-tablebordershow-overflowref="xTable1"height="300":row-config="{ isHover: true }":loading="loading"><vxe-column type="seq"></vxe-column><vxe-column field="id" title="ID"></vxe-column><vxe-column field="name" title="名字"></vxe-column><vxe-column field="value" title="对应值"></vxe-column></vxe-table></div>
</template><script>
import axios from "axios";
export default {data() {return {loading: false,};},async created() {this.loading = true;const res = await axios.get("http://ashuai.work:10000/bigData");this.loading = false;this.render(res.data.data);},methods: {render(data) {this.$nextTick(() => {const $table = this.$refs.xTable1;$table.loadData(data);});},},
};
</script>
复制代码

方案七 开启多线程Web Worker进行操作

本案例中,使用Web Worker另外开启一个线程去操作代码逻辑,收益并不是特别大(假如使用虚拟滚动列表插件的情况下)

不过也算是一个拓展的思路吧,面试的时候,倒是可以说一说,提一提。

Web Worker不熟悉的道友们,可以看看笔者之前的这篇文章:《性能优化之使用vue-worker插件(基于Web Worker)开启多线程运算提高效率》

方案八 未雨绸缪,防患于未然

以下为笔者愚见,仅供参考...

  • 在上述解决方案都说完以后,并没有结束。
  • 实际上本题目在考查候选人知识的广度和深度以外,更是考查了候选人的处理问题的思考方式,这一点尤其重要!
  • 笔者曾做过候选人去求职,也曾做过面试官去面试。就程序员开发工作而言,技术知识点不熟悉,可以快速学习,如文档、谷歌、百度、技术交流群,相关同事都可提供一定的支持
  • 更重要的是看中候选人的思考方式,思维模式
  • 试想,两个候选人实力水平差不多,但是一个只知道埋头苦干,有活就干,不去斟酌;而另外一个却是在用心工作的时候,也会仰望星空,会分析如何干活能够高性价比地完成任务,注重过程与结果
  • 这样的话,哪个更加受欢迎一些呢?

如果笔者是候选人,笔者在说了上述7种方案以后,会再补充第八种方案:未雨绸缪,防患于未然


场景模拟

面试官随意打量着其手中我的简历,抚须怪叫一声:“小子,后端要一次性返回10万条数据给你,你如何处理?”

我眉毛一挑,歪嘴一笑:“在上述7种方案陈述完以后,我想类似的问题,我们可以从根本上去解决。即第八种方案,要未雨绸缪,防患于未然。”

“哦?”面试官心中疑惑,缓缓放下我的简历:“愿闻其详。”

我不紧不慢地答道:“在具体开发工作中,我们在接到一个需求时,在技术评审期间,我们就要和后端去商量比较合适的技术解决方案。这个问题是后端要一次性返回我10万条数据,重点并不在10万条这么多数据,而在于后端为什么要这样做?”

面试官抬头,瞳孔中倒映出我的身影,认真听了起来。

我一字一顿地说道:“除去**业务真正需要这种方案**的话(若是客户要求的,那就没啥好说的,干就完了),后端这样做的原因大致有两种,第一种他不太懂sql的limit语句,但这基本不可能,第二种就是他有事情,随便敷衍写了一下。所以,就是要和他沟通,从大数据量接口请求时长过长,以及过多的dom元素渲染导致性能变差,以及项目的可维护性等角度去沟通,我相信只要正确的沟通,就能从根源上去避免这种不太合理的情况发生。”

面试官又突然狡黠地发问:“要是沟通以后,后端死活不给你分页呢?你咋办?嗨嗨!你的沟通无效果!你如何处理!人家不听你的!”似乎是觉得这个问题很刁钻,他双臂抱在胸前,靠在椅背上,发出桀桀桀的诡异笑声,他等待着看到我脸上即将绽放的回答不上来的,尴尬笑容。

我内心冷哼一声:雕虫小技...

我盯着面试官的眼睛,认真说道:“如果工作中沟通无效果,要么是我自己沟通语言表达的问题,这一点我会注意,不断提升自己的沟通技巧和说话方式,要么就是...”

我声音扬起了三分:“我沟通的这个人有问题!他工作摸鱼偷懒耍滑!固执己见!为难他人!高高在上!自以为是!这种情况下,我会找到我的直属领导去介入,因为这已经不是项目的需求问题了,而是员工的基本素养问题!”

停顿了一秒,我声音又柔和了几分:“但是,但是我相信咱们公司员工中是绝对没有这样的人存在的,各个都是能力强悍,态度端正的优秀员工。毕竟咱们公司在行业中久负盛名,我也是因此慕名而来的。您说对吧?”

面试官眼中闪过震惊之色,他没有想到我居然把皮球又踢给他了,不过他为了维持形象,旋即恢复了镇定,只是面部肌肉在止不住的微微颤抖。

“那是当然,公司人才济济。”面试官随口接话道。

我又补充道:“实际上在工作中,前端作为比较贴近用户的角色而言,需要和各个岗位的同事进行沟通,比如后端、产品、UI、测试等。我们需要通过合理的沟通方式,去提升工作效率,完成项目,实现自己的价值,为公司创造收益,我想这是每一个员工需要做的,也是必须要做到的。”

面试官又抚须怪叫一声:“小子表现还行,你被录用了!一个月工资2200,自带电脑,无社无金,007工作制,不能偷吃公司零食,以及...”

我:阿哒...

总结

有效的沟通,源自于解决问题的思维模式,在多数情况下,重要性,大于当下所掌握的技术知识点

  • 网站效果演示地址:ashuai.work:8888/#/bigData
  • GitHub仓库地址:github.com/shuirongshu…

 

相关文章:

后端要一次性返回我10万条数据

问题描述 面试官&#xff1a;后端一次性返回10万条数据给你&#xff0c;你如何处理&#xff1f;我&#xff1a;歪嘴一笑&#xff0c;what the f**k! 问题考察点 看似无厘头的问题&#xff0c;实际上考查候选人知识的广度和深度&#xff0c;虽然在工作中这种情况很少遇到... …...

汽车智能化「出海」红利

在高阶智能座舱中&#xff0c;车载导航产品作为与用户体验息息相关的模块之一&#xff0c;同样也进入了升级迭代周期。 基于高精度地图渲染、高精度定位算法、AR等技术的车道级导航、AR导航等产品快速上车&#xff0c;但同时随着人机交互多模发展以及3D沉浸式用户体验需求趋势下…...

Windows10资源管理器使用

文章目录 前言二、关联菜单操作1.分组展示2.添加选择复选框3.使用窗格模式4.功能区折叠二、“文件夹选项”对话框操作1.访问模式调整2.状态栏控制总结前言 目前Windows系统中的使用较多当属Windows10,资源管理器属于Windows系统中一个常用工具。本文总结了Windows 10 专业版下…...

【视频教程解读】Window上安装和使用autogluon V0.7

1.使用conda安装的python环境 教程使用的是极简版miniconda,由于我们的电脑中安装了anaconda&#xff0c;所以不需要进行进一步安装。python版本为3.9&#xff0c;博客里面有anaconda和python版本的对应关系。注意查看版本autogluon V0.4需要3.8或者3.9和3.10&#xff0c;pip版…...

10、Java继承与多态 - 内部类的概念与分类 1

10、Java继承与多态 - 内部类的概念与分类 1 什么是内部类&#xff1f; 如果一个事物的内部包含另一个事物&#xff0c;那么这就是一个内部包含另一个类&#xff0c;称作内部类&#xff1b; 例如&#xff1a;身体和心脏的关系&#xff0c;又如 -> 汽车和发动机的关系&#x…...

Java SE 面试题

文章目录 Java SE 面试题基本知识请简要介绍 Java SE。请解释 Java 的垃圾回收机制。请解释 Java 中的访问修饰符。 面向对象请解释封装、继承和多态。请解释接口和抽象类的区别。 集合框架请解释 ArrayList 和 LinkedList 的区别。请解释 Set 和 Map 接口。 异常处理请解释 Ja…...

Linux 之十九 编译工具链、.MAP 文件、.LST 文件

.map 文件和 .lst 文件是嵌入式开发中最有用的俩调试辅助文件。现在主要从事 RISC-V 架构&#xff0c;开始与 GCC 打交道&#xff0c;今天就重点学习一下 GCC 的 .map 文件、.lst 文件&#xff0c;并辅助以 ARMCC 和 IAR 作为对比。 编译工具链 .map 文件和 .lst 文件都是由编…...

小 C 的数学(math)

祝大家劳动节快乐&#xff01;&#xff01;小手动起来 言归正传┏ (゜ω゜)☞ 题目描述 小 C 想要成为一名 OIer&#xff0c;于是他提前学习数学&#xff0c;为 OI 做好铺垫。这一天&#xff0c;他的数学老师给了一道题&#xff1a;给定正整数 a&#xff0c;以及给定一个区间 …...

应用运行环境实时洞察,亚马逊云科技Cisco AppDynamics展优势

Cisco AppDynamics(APM)产品&#xff0c;现已正式上线亚马逊云科技Marketplace&#xff08;中国区域&#xff09;。可以通过亚马逊云科技Marketplace&#xff08;中国区域&#xff09;网站&#xff0c;灵活便捷地部署该解决方案&#xff0c;以便充分利用云原生APM(应用性能管理…...

C++程序设计——lambda表达式

一、问题引入 在C98中&#xff0c;如果想对一个数据集合中的元素进行排序&#xff0c;可以使用sort()方法&#xff0c;但如果待排序元素为自定义类型&#xff0c;就需要用户自己定义排序时的比较规则。 随着C语法的发展&#xff0c;人们开始觉得其编写比较复杂&#xff0c;每次…...

Unity 高级程序员应该具备怎样的能力?要怎样成长为 Unity 高级程序员?

如何从零基础小白成长为 Unity 高级程序员&#xff1f;【全篇学习内容免费&#xff01;快来白嫖】 高能预警&#xff0c;下文包含从零基础新手到高级程序员一站式技术学习、学习方法、心态等内容&#xff0c;供各个阶段的同学进行参考。 从零基础到高级程序员 上干货 话不多说…...

禁止触摸屏触控板手指缩放,需要这样处理

要禁止触摸屏的手指缩放&#xff0c;可以使用如下的CSS 只要在页面上使用css样式touch-action: none&#xff0c;就能禁止web在手机或平板上的缩放了。 <html style"touch-action: none;">注意&#xff1a; 使用 touch-action: none作用于html元素上&#xff0…...

opencv cuda版本windows编译

目录 1. 编译准备2. 编译3. 遇到的问题及解决方案3.1 boostdesc_bgm.i,vgg_generated_48.i等文件的缺失3.2 fatal error: features2d/test/test_detectors_regression.impl.hpp: 没有那个文件或目录 1. 编译准备 编译工具是cmakevisual studio2022&#xff0c;首先安装这两个工…...

python哲学

进入python编辑器模式下&#xff0c;输入import this 会打印python之禅(The Zen of Python) Beautiful is better than ugly. 优美胜于丑陋。 Explicit is better than implicit. 明了胜于晦涩。 Simple is better than complex. 简单胜过复杂。 Complex is better than co…...

(2023)用AIGC写iOS项目单元总结

尝试开发的项目 项目功能 用 ChatGPT 开发了一个视频播放器。需要它编写的功能包括&#xff1a; ☆ 本地文件&#xff0c;在线 URL 播放&#xff0c;暂停 ☆ 点击空白区域弹出操作菜单&#xff0c;再点击消失 ☆ 手动横竖屏切换 ☆ 播放速度调整&#xff0c;限定 0.5, 1.0, …...

k8s扩容node节点会影响上面已存在的pod吗?

理论上不影响 扩容 Kubernetes 集群中的节点不会影响已经运行的 Pod&#xff0c;因为 Pod 是在节点上运行的&#xff0c;而不是在集群中运行的。当您添加新的节点时&#xff0c;Kubernetes 调度器会在新节点上启动新的 Pod&#xff0c;而已经运行的 Pod 会继续在它们当前的节点…...

深度学习 -- pytorch 计算图与动态图机制 autograd与逻辑回归模型

前言 pytorch中的动态图机制是pytorch这门框架的优势所在&#xff0c;阅读本篇博客可以使我们对动态图机制以及静态图机制有更直观的理解&#xff0c;同时在博客的后半部分有关于逻辑回归的知识点&#xff0c;并且使用pytorch中张量以及张量的自动求导进行构建逻辑回归模型。 …...

计算机网络学习03(OSI、TCP/IP网络分层模型详解))

1、OSI 七层模型 OSI 七层模型 是国际标准化组织提出一个网络分层模型&#xff0c;其大体结构以及每一层提供的功能如下图所示&#xff1a; 每一层都专注做一件事情&#xff0c;并且每一层都需要使用下一层提供的功能比如传输层需要使用网络层提供的路由和寻址功能&#xff0…...

ChatGPT是什么?ChatGPT里的G、P、T分别指什么

文章目录 ChatGPT是什么GTP中的 生成式 是什么意思GTP中的 预训练 是什么意思GTP中的 变换模型 是什么意思 什么是Transformer什么是注意力机制 监督学Xi、无监督学Xi、强化学Xi ChatGPT是什么 GPT: Generative Pre-trained Transformer 生成式预训练变换模型 ChatGPT是由Ope…...

Linux服务使用宝塔面板搭建网站,并发布公网访问 - 内网穿透

文章目录 前言1. 环境安装2. 安装cpolar内网穿透3. 内网穿透4. 固定http地址5. 配置二级子域名6. 创建一个测试页面 转载自远程内网穿透的文章&#xff1a;Linux使用宝塔面板搭建网站&#xff0c;并内网穿透实现公网访问 前言 宝塔面板作为简单好用的服务器运维管理面板&#…...

TDA4VH j784s4 使用

// sdk https://www.ti.com/tool/PROCESSOR-SDK-J784S4 // Jacinto Processors TDA4AP-Q1/TDA4VP-Q1/TDA4AH-Q1/TDA4VH-Q1 EVM User’s Guide https://www.ti.com/lit/ug/spruj62/spruj62.pdf?ts1682337275236&ref_urlhttps%253A%252F%252Fwww.ti.com%252Fsitesearch%252…...

CSS布局基础(字体,文本,背景)

字体 常见字体设置 body {font-family: font-family: "Microsoft YaHei", Tahoma, Arial, Hiragino Sans GB,sans-serif; }浏览器从前到后匹配&#xff0c;找到可用字体结束&#xff0c;都没匹配上&#xff0c;使用浏览器默认字体 常用字号 不同浏览器默认字号可…...

Redis入门指南:深入了解这款高性能缓存数据库

本文将带您了解Redis的基本概念、数据类型、特性以及如何在实际项目中应用Redis。通过阅读本文&#xff0c;您将更好地理解如何利用Redis优化您的应用程序性能。 1. 什么是Redis&#xff1f;2. Redis的数据类型3. Redis的特性4. 如何使用Redis4.1 安装与启动4.2 基本命令4.3 应…...

# 数据结构和算法面试题系列-随机算法总结

0 概述 随机算法涉及大量概率论知识&#xff0c;有时候难得去仔细看推导过程&#xff0c;当然能够完全了解推导的过程自然是有好处的&#xff0c;如果不了解推导过程&#xff0c;至少记住结论也是必要的。本文总结最常见的一些随机算法的题目&#xff0c;是几年前找工作的时候…...

windows中vscode配置C/C++环境

首先要把MinGW的环境安装完&#xff0c;我一般是下载带有MinGW的codeblocks&#xff0c;这样省去自己安装MinGW。因为安装MinGW还挺麻烦的。 安装完codeblocks&#xff0c;找到其安装目录&#xff0c;把bin文件配置到环境变量去&#xff1a; 将bin添加到环境变量 然后打开vsco…...

shell编程之条件语句

shell编程之条件语句 一、条件测试操作1.test命令2.文件测试3.利用条件判断&#xff0c;创建文件4.整数值比较4.1 常用的测试操作符 5.字符串比较5.1 常用的测试操作符 6.逻辑测试6.1 常用的测试操作符 二、if语句的结构1.单分支结构2.双分支结构3.多分支结构4.if嵌套 三、case…...

【Python每日十题菜鸟版--第二天】

菜鸟实例 &#x1f349;前言1.判断奇偶性2.判断闰年3. 获取最大值最小值4. 质数&#xff08;素数&#xff09;的判断5.阶乘方法一方法二 6.九九乘法表7.斐波那契数列方法一 &#xff1a;循环计算法&#xff08;一般方法&#xff09;方法二&#xff1a; 递归 8.阿姆斯特朗数9. 十…...

拓扑排序模板及例题

概念 一个有向无环图必然存在一个拓扑序列与之对应。 流程&#xff1a; 先将所有入度为0的节点入队将队列中的节点出队&#xff0c;出队序列就是对应拓扑序。对于弹出的节点x&#xff0c;遍历x所有出度y&#xff0c;对y进行入读减一操作检查入度减一之后的节点y&#xff0c;…...

linux查看nginx安装路径

linux查看nginx安装路径 有几种方法可以查看nginx的安装路径: 使用which命令: which nginx这个命令会返回nginx的二进制文件路径,一般也是安装路径。 查看nginx的进程,得到安装路径: ps aux | grep nginx输出结果中有nginx的进程路径,这个也是安装路径。 在nginx的配置文…...

【生态环境保护】绿水青山就是金山银山——生态环保篇

环保是一个持续性的话题&#xff0c;不仅仅是在国内&#xff0c;整个世界都是一个命运共同体从城市垃圾分类&#xff0c;到农村/村镇污水治理&#xff0c;城乡一体化和因地制宜的实施方式&#xff0c;是我们一直在探索的。 从余村到全国&#xff0c;从中国到世界&#xff0c;“…...